2010-04-17 8 views
8

Đây là từ một thư viện nhỏ mà tôi tìm thấy trực tuyến:Trở lại 'c_str' từ một hàm

const char* GetHandStateBrief(const PostFlopState* state) 
{ 
    static std::ostringstream out; 

    // ... rest of the function ... 

    return out.str().c_str() 
} 

Trong mã của tôi, tôi đang làm điều này:

const char *d = GetHandStateBrief(&post); 
std::cout<< d << std::endl; 

Bây giờ, lúc đầu d chứa rác . Sau đó tôi nhận ra rằng chuỗi C tôi nhận được từ hàm bị hủy khi hàm trả về vì std::ostringstream được cấp phát trên ngăn xếp. Vì vậy, tôi đã thêm:

return strdup(out.str().c_str()); 

Và bây giờ tôi có thể nhận được văn bản tôi cần từ hàm.

Tôi có hai câu hỏi:

  1. Tôi hiểu điều này một cách chính xác?

  2. Sau đó tôi nhận thấy rằng out (loại std::ostringstream) được cấp phát bằng bộ nhớ tĩnh. Điều đó không có nghĩa là đối tượng được cho là phải ở trong bộ nhớ cho đến khi chương trình kết thúc? Và nếu có thì tại sao chuỗi không thể truy cập được?

Trả lời

11

strdup phân bổ một bản sao của chuỗi trên heap, mà bạn phải giải phóng bằng tay sau (với free() tôi nghĩ). Nếu bạn có tùy chọn, sẽ tốt hơn nếu trả lại std::string.

Bộ nhớ tĩnh của out không hiệu quả, vì .str() trả về tạm thời std::string, bị hủy khi chức năng thoát.

-1

Trong GetHandStateBrief, biến out không cần tĩnh. Bạn cần một rõ ràng static string để thay thế tạm thời mà đã được tạo ra trong cuộc gọi ban đầu của bạn để out.str():

static std::string outStr; 
std::ostringstream out; 
... rest of function ... 
outStr = out.str(); 
return outStr.c_str(); 
+1

Điều này rất nguy hiểm. Trả về 'char *' không được bảo đảm là hợp lệ sau một cuộc gọi tiếp theo tới 'GetHandStateBrief'. –

+0

Đúng là mọi lời gọi đến 'GetHandStateBrief' sẽ làm mất hiệu lực con trỏ được trả về bởi cuộc gọi trước đó. Nguy cơ là bối cảnh phụ thuộc mặc dù. –

+1

downvote cho nguy cơ bắn mình vào chân? –

0

strdup() trả về một con trỏ char * được trỏ đến bộ nhớ trên heap. Bạn cần phải giải phóng() khi bạn hoàn thành nó, nhưng có, điều đó sẽ hiệu quả.

Biến cục bộ tĩnh std::ostringstream out không có ý nghĩa trong trường hợp này, trừ khi chuỗi std :: được trả về cũng tĩnh mà quan sát của bạn hiển thị là không đúng.

3

Bạn nói đúng rằng out là biến tĩnh được phân bổ trên phân đoạn dữ liệu. Nhưng out.str() tạm thời được phân bổ trên ngăn xếp. Vì vậy, khi bạn thực hiện return out.str().c_str(), bạn sẽ trả về con trỏ cho dữ liệu nội bộ của một ngăn xếp tạm thời. Lưu ý rằng ngay cả khi chuỗi không phải là biến ngăn xếp, thì c_str là "chỉ được cấp để không thay đổi cho đến khi cuộc gọi tiếp theo đến một hàm thành viên không liên tục của đối tượng chuỗi".

Tôi nghĩ bạn đã đạt được giải pháp hợp lý, giả sử bạn không thể chỉ trả lại chuỗi.

+2

Hmm, "biến tĩnh được phân bổ trên heap" - không bao giờ nghe nói về điều đó :) –

+0

Cảm ơn bạn đã đánh bắt điều đó. –

+3

Vâng, dữ liệu ký tự của chuỗi thực sự được lưu trữ trên heap với bất kỳ chuỗi std :: nào, dù là tĩnh hay bất kỳ thứ gì. Đó là bộ mô tả chuỗi được lưu trữ trên phân đoạn dữ liệu giống như các biến khác với tuổi thọ toàn cầu. –