2012-04-11 9 views
5

Tôi có một vài câu hỏi mà tôi nghĩ sẽ khá dễ dàng đối với người có trải nghiệm C++ để trả lời, tôi sẽ in đậm quesitons cho TL; DRC-Style strings to std :: làm rõ chuỗi chuyển đổi

với đoạn mã sau:

void stringTest(const std::string &s) 
{ 
    std::cout << s << std::endl; 
} 

int main() 
{ 
    stringTest("HelloWorld"); 
} 

Hopefuly ai đó có thể chỉ ra những sai sót trong quá trình suy nghĩ của tôi ở đây:

tại sao tham số trong stringTest đã được đánh dấu const khi đã thông qua một chuỗi C-Style? Không có chuyển đổi ẩn đối với chuỗi std :: diễn ra bằng cách sử dụng hàm tạo chuỗi cstyle của nó, do đó "s" không còn là tham chiếu đến một chữ (và không bắt buộc phải là const).

Hơn nữa, điều gì sẽ một chuỗi cstyle constructor cái nhìn như thế nào, và làm thế nào để trình biên dịch biết để gọi này khi nhìn thấy:

stringTest("HelloWorld"); 

Liệu nó chỉ đơn giản là nhận ra một chuỗi chữ là một cái gì đó giống như một char * ?

Tôi đã tình cờ gặp những câu hỏi này trong khi nghiên cứu các nhà thầu sao chép. Một quesiton nhanh chóng làm rõ của riêng tôi ...

Trong trường hợp của một cái gì đó như:

std::string s = "HelloWorld"; 

là các nhà xây dựng chuỗi cstyle sử dụng để nhanh chóng một std :: string tạm thời, và sau đó là chuỗi tạm thời là sao chép vào "s" bằng cách sử dụng constructor chuỗi sao chép?:

std::string(const std::string&); 
+0

"Tại sao tham số trong stringTest phải được đánh dấu const" - bất kể khi nào _necessary_, bạn muốn tạo tham chiếu _all_ 'const' không thực sự được sửa đổi. – leftaroundabout

+0

@leftaroundabout: Điểm công bằng, tôi chắc chắn sẽ làm điều này với trái tim. – Riken

+0

có thể trùng lặp của [Làm thế nào đến một tham chiếu không const không thể liên kết với một đối tượng tạm thời?] (Http://stackoverflow.com/questions/1565600/how-come-a-non-const-reference-cannot-bind-to -a-tạm thời-đối tượng) –

Trả lời

2

Tại sao tham số trong stringTest đã được đánh dấu const khi đã thông qua một chuỗi C-Style?

Nó chỉ có khi tham số là một tài liệu tham khảo, vì tạm thời std::string được xây dựng từ char const* bạn vượt qua trong và const tài liệu tham khảo không để tạm thời là bất hợp pháp.

Đơn giản là nhận ra chuỗi có chữ giống như char *?

Chuỗi ký tự là một mảng char const, phân hủy thành char const*. Từ đó, trình biên dịch infers rằng nó nên sử dụng non- explicit constructor std::string::string(char const *) để xây dựng tạm thời.

Là hàm tạo kiểu cstyle dùng để khởi tạo chuỗi std tạm thời :: và sau đó chuỗi tạm thời được sao chép vào "s" bằng cách sử dụng hàm tạo bản sao chuỗi?

Hơi phức tạp hơn một chút. Có, tạm thời được tạo. Nhưng trình tạo bản sao có thể hoặc không thể được gọi; trình biên dịch được phép bỏ qua việc xây dựng bản sao dưới dạng tối ưu hóa.Các nhà xây dựng bản sao vẫn phải được cung cấp, mặc dù, vì vậy sau đây sẽ không biên dịch:

class String { 
    String(char const *) {} 
    private: 
    String(String const &); 
}; 

int main() 
{ 
    String s = ""; 
} 

Ngoài ra, trong C++ 11 nhà xây dựng thái này sẽ được sử dụng, nếu được cung cấp; trong trường hợp đó, hàm tạo bản sao là không cần thiết.

+0

+1 nhưng bạn có thể (nên) làm rõ rằng trong trường hợp thứ ba, mặc dù các nhà xây dựng bản sao là * yêu cầu *, nó không thực sự viện dẫn bởi vì nó sẽ (luôn luôn - bất kể tối ưu hóa?) được elided . Điều này khá quan trọng mặc dù đó là "chỉ" một tối ưu hóa được phép. –

+0

Một chuỗi ký tự không có 'char const *', nó là 'char const [N]', tất nhiên có thể chuyển đổi thành 'char const *' –

+0

@KonradRudolph: đã làm điều đó và mở rộng một chút trên bản sao/di chuyển điều xây dựng. –

0

const string & s trong ví dụ này được yêu cầu để gọi hàm tạo từ đối số "HelloWorld". Hàm tạo được sử dụng là xây dựng kiểu chuyển đổi.

A string& s sẽ không thực hiện vì s đang trực tiếp tham chiếu một đối tượng chuỗi.

Việc chuyển đổi loại được xác định bởi một cái gì đó tương tự như

basic_string(const _CharT* __s); 

Với một typedef

typedef basic_string<char> string; 

Vì vậy, việc kê khai sẽ đánh giá để

basic_string(const char * __s)  
+0

Điều đó * âm thanh * sai. Hoặc là bạn bị nhầm lẫn hoặc giải thích là không rõ ràng. Dù bằng cách nào, 'const' là * not * cần thiết để gọi một hàm tạo bản sao. –

+0

@KonradRudolph Nghe có vẻ sai vì nó sai, nắp suy nghĩ của tôi đã bị lùi lại. –

2

Tại sao tham số trong stringTest phải được đánh dấu const khi đã vượt qua một chuỗi C-Style?

EDIT: Thời gian phải không thay đổi. Xem nhận xét và câu trả lời của larsmans, anh ấy đúng.

lý do đơn giản:

void change(std::string& c) { c = "abc"; } 
change("test"); // what should the code exactly do?? 

Bên cạnh đó, những gì sẽ là một chuỗi cstyle constructor cái nhìn như thế nào, và làm thế nào để trình biên dịch biết để gọi này khi nhìn thấy:

Nó ngước lên std::string cho string(char*) constructor

Trong trường hợp thứ hai ing như:

std::string s = "HelloWorld"; 

là các nhà xây dựng cstyle sử dụng để nhanh chóng một std :: string tạm thời, và sau đó là chuỗi tạm thời được sao chép vào "s" bằng cách sử dụng constructor chuỗi bản sao ?: std :: string (std const :: string &);

Không. Trong trường hợp chính xác này (TYPE variable = SOMETHING), nó giống như viết TYPE variable(SOMETHING);. Vì vậy, không có sao chép được sử dụng.

+0

Điểm đầu tiên và thứ ba của bạn là sai. –

+0

@Konrad, bạn có chắc chắn rằng điểm thứ ba là sai? – nothrow

+0

Có ... xem câu trả lời của larsmans (nhưng cũng bình luận của tôi bên dưới nó). –

2

Nó có đơn giản nhận ra một chuỗi chữ giống như một chữ cái char * không?

Phần này của câu hỏi gốc chưa được trả lời rõ ràng như tôi đã thích. Tôi hoàn toàn xác nhận (và được bình chọn) câu trả lời của Yossarian cho phần còn lại.

Về cơ bản, bạn cần hiểu trình biên dịch đang làm gì khi thấy chuỗi ký tự trong mã.Mảng ký tự đó (như bất kỳ chuỗi kiểu c nào thực sự) được lưu trữ ở một vị trí hoàn toàn khác với mã nó là một phần của (tùy thuộc vào kiến ​​trúc, các chữ số có thể được lưu trữ tại vị trí của nó như một phần của assembly) lệnh nhị phân). Hai khối mã ở đây là "nhiều hay ít" tương đương (bỏ qua thiếu bao gồm hoặc tờ khai namespace):

int main(void) 
{ 
    cout << "Hello!" << endl; 
    return 0; 
} 

Đây là gần gũi hơn với những gì "thực sự" xảy ra:

const char HELLO_STR[] = { 'H', 'e', 'l', 'l', 'o', '!', 0 }; 

int main(void) 
{ 
    cout << HELLO_STR << endl; 
    return 0; 
} 

Hãy tha thứ cho tôi nếu Tôi đã thực hiện một lỗi trong init mảng hoặc bất cứ điều gì, nhưng tôi nghĩ rằng điều này thể hiện những gì tôi có nghĩa là đối với nơi chuỗi chữ "thực sự" được lưu trữ. Nó không phải là nội tuyến, nhưng là một hằng số vô hình cho một phần khác của chương trình mà nó được định nghĩa. Ngoài ra, một số trình biên dịch cũng có thể sắp xếp các chuỗi ký tự "cùng nhau" để nếu bạn có cùng một chữ được sử dụng ở 50 vị trí, nó chỉ lưu trữ một trong số chúng và tất cả đều tham chiếu đến cùng một hằng số, tiết kiệm bộ nhớ. Vì vậy, hãy nhớ rằng bất cứ lúc nào bạn đang sử dụng một chuỗi chữ, bạn đang sử dụng một const char [N] tồn tại "vô hình" ở đâu đó, được chuyển đổi hoàn toàn thành const char *.