2012-07-06 26 views
6

Tôi vẫn đang học C++, vì vậy hãy chịu với tôi. Tôi đang viết một trình bao bọc đơn giản xung quanh các đường dẫn hệ thống tập tin nâng cao - Tôi gặp phải các vấn đề lạ khi trả về các chuỗi tạm thời. Đây là lớp học đơn giản của tôi (đây không phải là chính xác, nhưng khá gần):Tạm thời std :: strings return junk

typedef const char* CString; 
typedef std::string String; 
typedef boost::filesystem::path Path; 

class FileReference { 

    public: 

     FileReference(const char* path) : mPath(path) {}; 

     // returns a path 
     String path() const { 
      return mPath.string(); 
     }; 

     // returns a path a c string 
     CString c_str() const { 
      return mPath.string().c_str(); 
     }; 

    private: 

     Path mPath; 

} 

Với mã thử nghiệm nhỏ dưới đây:

FileReference file("c:\\test.txt"); 

OutputDebugString(file.path().c_str()); // returns correctly c:\test.txt 
OutputDebugString(file.c_str());  // returns junk (ie îþîþîþîþîþîþîþîþîþîþî.....) 

Tôi khá chắc chắn điều này có để đối phó với temporaries, nhưng tôi không thể hiểu tại sao điều đó sẽ - không phải mọi thứ đều sao chép chính xác?

+0

nguồn của 'OutputDebugString()' là gì? –

+2

Đã gắn kết tại 'typedef''ing của riêng bạn' CString' ... – Blindy

+1

@OttoAllmendinger - Nó là [Windows API] (http://msdn.microsoft.com/en-us/library/windows/desktop/aa363362 (v = vs.85) .aspx). –

Trả lời

4

Có vẻ như mPath.string() trả về một chuỗi theo giá trị. Đối tượng chuỗi tạm thời đó bị hủy ngay khi FileReference :: c_str() trả về, vì vậy hàm c_str() của nó trở thành không hợp lệ. Với mô hình như vậy, không thể tạo hàm c_str() mà không giới thiệu một số loại biến cấp lớp hoặc tĩnh cho chuỗi.

Hãy xem xét các lựa chọn thay thế sau:

//Returns a string by value (not a pointer!) 
//Don't call it c_str() - that'd be misleading 
String str() const 
{    
    return mPath.string(); 
} 

hoặc

void str(String &s) const 
{    
    s = mPath.string(); 
} 
+0

Sử dụng hợp lệ cho đề xuất đầu tiên sẽ là 'OutputDebugString (file.str(). c_str()); ' –

8
CString c_str() const { 
     return mPath.string().c_str(); 
    }; 

mPath.string() trả về một bản sao của một std::string. Bản sao đó được lưu trữ tạm thời và sẽ bị hủy ở cuối biểu thức này.

.c_str() trả về con trỏ tới bộ nhớ sẽ bị hủy khi chuỗi bị hủy, tức là ở cuối biểu thức này.

Bạn đang trả lại con trỏ tới bộ nhớ đã bị hủy.

+1

nếu anh ấy muốn một con trỏ, anh ta có thể trả lại m_path.c_str() – PermanentGuest

+0

@PermanentGuest - bạn có chắc chắn không? Tôi không thể tìm thấy '.c_str()' trong tài liệu Boost.Filesystem [http://www.boost.org/doc/libs/1_41_0/libs/filesystem/doc/reference.html#Class-template- basic_path). –

+0

@ Robᵩ: Những tài liệu đó gần ba tuổi. [_current_ docs] (http://www.boost.org/doc/libs/1_50_0/libs/filesystem/doc/reference.html#path-native-format-observers) đề cập đến nó. ; -] (Điều này có thể đã được thêm vào trong FileSystem v3.) – ildjarn

0

Expressions

OutputDebugString(file.path().c_str()) 

OutputDebugString(file.c_str()) 

cũng tương tự như ở chỗ cả hai đều có hiệu quả gọi c_str() phương thức trên một đối tượng tạm thời std::string và cố gắng sử dụng các kết quả của cuộc gọi đó. Người đầu tiên gọi nó trực tiếp là file.path().c_str() biểu hiện phụ. Điều thứ hai là nó ngầm hơn: bên trong phương thức FileReference::c_str().

Trong trường hợp đầu tiên đối tượng tạm thời std::string được tạo rõ ràng bằng cách gọi file.path() gọi là một phần ngay lập tức của toàn bộ biểu thức. Theo các quy tắc của ngôn ngữ, tuổi thọ của đối tượng tạm thời đó kéo dài đến cuối toàn bộ biểu thức, đó là lý do tại sao tạm thời và kết quả của cuộc gọi c_str() vẫn hợp lệ trong suốt.

Trong trường hợp thứ hai, đối tượng tạm thời std::string được tạo bên trong phương thức FileReference::c_str(). Đối tượng tạm thời đó bị hủy khi phương thức này trả về, nghĩa là FileReference::c_str() trả về một con trỏ tới dữ liệu "đã chết". Đây là lý do cho "rác" trong câu hỏi.

Các vấn đề liên quan