2011-11-09 60 views
20

Tôi đang học C++ ngay từ đầu và tôi không nhận được toàn bộ chuỗi chủ đề.Khai báo chuỗi C++

Sự khác biệt giữa ba mã sau là gì?

  1. std::string s = std::string("foo");
  2. std::string s = new std::string("foo");
  3. std::string s = "foo";
+0

Lưu ý rằng bạn thường muốn sử dụng tùy chọn 4: 'std :: string s (" foo ");' –

+0

@JerryCoffin: khác với phương án 3 như thế nào? –

+2

@MikeSeymour: nó khởi tạo trực tiếp thay vì khởi tạo sao chép. Ít nhất là khái niệm, # 3 tạo ra một chuỗi tạm thời được khởi tạo từ hằng số được cung cấp, sau đó sử dụng hàm tạo bản sao để tạo 's' từ giá trị đó (mặc dù, phải thừa nhận rằng trình biên dịch sẽ thường bỏ qua và thực hiện tương đương khởi tạo trực tiếp). –

Trả lời

32
std::string s = std::string("foo"); 

Điều này tạo ra một đối tượng tạm thời std::string chứa "foo", sau đó gán nó vào s. (Lưu ý rằng các trình biên dịch có thể bỏ tạm thời. Các elison tạm thời trong trường hợp này được cho phép một cách rõ ràng theo tiêu chuẩn C++.)

std::string s = new std::string("foo"); 

Đây là lỗi trình biên dịch. Biểu thức new std::string("foo")tạo một số std::string trên cửa hàng miễn phí và trả về con trỏ đến std::string. Sau đó, nó cố gắng chỉ định con trỏ được trả về loại std::string* đến s của loại std::string. Thiết kế của lớp std::string ngăn điều đó xảy ra, do đó việc biên dịch không thành công.

C++ không phải là Java. Đây không phải là cách các đối tượng thường được tạo ra, bởi vì nếu bạn quên delete đối tượng trả về std::string bạn sẽ bị rò rỉ bộ nhớ. Một trong những lợi ích chính của việc sử dụng std::string là nó quản lý bộ đệm chuỗi cơ bản cho bạn một cách tự động, do đó, new -ing nó là loại thất bại nhằm mục đích.

std::string s = "foo"; 

Điều này về cơ bản giống như # 1. Về mặt kỹ thuật, nó khởi tạo một chuỗi tạm thời mới chứa "foo", sau đó gán nó cho s. Một lần nữa, các trình biên dịch thường sẽ giải thích tạm thời (và thực tế là tất cả các trình biên dịch không ngu ngốc ngày nay thực tế loại bỏ tạm thời), vì vậy trong thực tế nó chỉ đơn giản là xây dựng một đối tượng mới có tên là s.

Cụ thể nó gọi một hàm tạo chuyển đổi trong std::string chấp nhận đối số const char*. Trong đoạn mã trên, hàm khởi tạo chuyển đổi được yêu cầu là không explicit, nếu không thì đó là lỗi trình biên dịch. Nhà xây dựng chuyển đổi thực tế là không phải explicit cho std::string s, vì vậy việc biên dịch trên không biên dịch.

Đây là cách std::string s thường được khởi tạo. Khi s vượt quá phạm vi, đối tượng s sẽ bị hủy cùng với bộ đệm chuỗi cơ bản. Lưu ý rằng sau đây có tác dụng tương tự (và là một cách điển hình khác std::string s được khởi tạo), theo nghĩa nó cũng tạo ra một đối tượng có tên là s chứa "foo".

std::string s("foo"); 

Tuy nhiên, there's a subtle difference between std::string s = "foo"; and std::string s("foo");, một trong số đó là các nhà xây dựng chuyển đổi có thể là explicit hoặc phi explicit trong trường hợp trên.

+2

+1 là câu trả lời đề cập đến trình biên dịch không nhất thiết tạo ra tạm thời trong # 1. –

+1

Lưu ý rằng # 1 và # 3 tương đương với ngôn ngữ liên quan. – avakar

+0

Vì vậy, 'std :: string (" foo ")' tạo "foo" trên stack và 'new std :: string (" foo ")' tạo foo trên heap? –

2
  1. Tạo một đối tượng tạm thời chuỗi và sao chép giá trị cho s
  2. Không biên dịch, new std::string("foo") trả về một con trỏ đến một số bộ nhớ vừa được cấp phát. Để làm việc này, bạn nên khai báo s như một con trỏ đến một chuỗi std::string* s.
  3. Tạo chuỗi từ chuỗi C.

Bạn nên sử dụng tùy chọn thứ ba nhiều nhất - nếu không phải tất cả các trường hợp.

2

1 sẽ tạo một biến tạm thời (ngay phía bên tay), sau đó gọi toán tử gán để gán giá trị cho s

2 sẽ tạo ra một thể hiện của std::string trên heap và trả về một con trỏ đến nó, và sẽ thất bại trong việc chuyển nhượng vì bạn không thể gán một con trỏ đến một loại phi con trỏ

3 sẽ xây dựng một std :: string và khởi tạo nó từ một const char*

+0

"bạn không thể gán con trỏ cho loại không phải con trỏ": Theo ý kiến ​​của bạn thì 'bool s; s = new std :: string ("Hello, world."); 'là một lỗi biên dịch thời gian? BTW rằng dấu bằng không phải là một nhiệm vụ (ví dụ, nó có thể hợp pháp để viết 'Foo x = 12;' ngay cả khi 'Foo :: operator = (int)' là riêng tư). – 6502

+0

@ 6502: Từ ngữ của anh sai, nhưng không thể gán từ 'std :: string' –

+0

@MooingDuck: Câu trả lời này chỉ đơn giản là sai trên một vài điểm: A) đó không phải là bài tập, là khởi tạo (trong C++ nó là một điều khác, với các quy tắc và ngữ nghĩa khác nhau, toán tử gán trả lời các câu hỏi trong 1 là * NOT * được gọi), B) Cụm từ "Bạn không thể gán con trỏ cho kiểu không phải con trỏ" là sai. .. bạn có thể gán (và cũng khởi tạo) một boolean từ một con trỏ. Điểm 2 có IMO một từ ngữ rất xấu vì có vẻ như nó nói rằng mã sẽ biên dịch và một sẽ nhận được một lỗi thời gian chạy ... nhưng ít nhất có một số nghi ngờ điều này không phải là những gì Fred có nghĩa là. – 6502

0

trên số 1, bạn đang tạo ra một tạm thời chuỗi bằng cách sử dụng hàm tạo và sau đó gán nó cho s. Số 2 thậm chí không biên dịch. Trên số 3, bạn đang tạo một chuỗi mới và sau đó gán một giá trị cho nó.

3
std::string s = std::string("foo"); 

Điều này được gọi là khởi tạo bản sao. Nó có chức năng giống như khởi tạo trực tiếp

std::string s("foo"); 

nhưng cựu không đòi hỏi rằng các nhà xây dựng bản sao có sẵn và trình biên dịch có thể tạo ra một đối tượng tạm thời nhưng hầu hết sẽ bõ mẫu âm chót tạm thời và trực tiếp xây dựng s chứa "foo".


std::string s = new std::string("foo"); 

này sẽ không biên dịch vì new trả về một con trỏ. Để hoạt động, bạn cần loại sstd::string *. Sau đó, dòng động phân bổ một đối tượng std::string và lưu con trỏ trong s. Bạn sẽ cần phải delete nó sau khi bạn đã sử dụng xong.


std::string s = "foo"; 

này là gần như giống như lần đầu tiên. Nó là bản sao khởi tạo nhưng nó có thêm một ràng buộc. Yêu cầu rằng lớp std::string chứa một hàm tạo không phải là explicit mất const char *. Điều này cho phép trình biên dịch ngầm xây dựng một đối tượng std::string tạm thời. Sau đó ngữ nghĩa giống hệt với trường hợp 1.