2011-01-19 31 views
8

xin lỗi vì một câu hỏi dài nhưng tôi cố gắng càng rõ ràng càng tốt. Điều này bằng cách nào đó sau câu hỏi trước của tôi về strings in C++. Tôi đang cố gắng tìm ra cách tôi có thể trở lại std :: chuỗi từ một chức năng mà không cần phân bổ bộ nhớ thừa, mà không dựa vào NRVO. Những lý do tại sao tôi không muốn dựa vào NRVO là:STL hoán đổi khi trở về?

  • nó không được hỗ trợ bởi trình biên dịch, chúng tôi hiện đang sử dụng
  • ngay cả khi nó được hỗ trợ nó có thể không luôn luôn được kích hoạt trong chế độ Debug
  • nó có thể thất bại trong một số trường hợp (example)

Xin lưu ý rằng tôi cần một giải pháp tương thích C++ 03 (không C++ 0x rvalue tài liệu tham khảo do đó, không may ...)

Các si mplest cách làm điều này là pass-by-reference và làm std :: hoán đổi, như thế này

void test(std::string& res) 
{ 
    std::string s; 
    //... 
    res.swap(s); 
} 

Nhưng đó là tự nhiên hơn và thường thuận tiện hơn để trở lại theo giá trị hơn vượt qua bằng cách tham khảo, vì vậy những gì tôi muốn đạt được là thế này:

std::string test() 
{ 
    std::string s; 
    //... 
    return SOMETHING(s); 
} 

Lý tưởng nhất là nó sẽ chỉ làm một swap với "giá trị trả về", nhưng tôi không thấy làm thế nào để làm điều này trong C++. Có auto_ptr đã được di chuyển thay vì sao chép, và tôi thực sự có thể sử dụng auto_ptr<string>, nhưng tôi muốn tránh tự động phân bổ đối tượng chuỗi chính nó.

Ý tưởng của tôi là bằng cách nào đó "gắn thẻ" một đối tượng chuỗi mà nó đang được trả về từ một hàm để cho phép di chuyển dữ liệu của nó khi hàm tạo bản sao được gọi trở lại. Vì vậy, tôi đã kết thúc với mã này, mà thực hiện chính xác những gì tôi muốn:

struct Str 
{ 
    struct Moveable 
    { 
     Str & ref; 
     explicit Moveable(Str & other): ref(other) {} 
    }; 

    Str() {} 
    Str(const std::string& other) : data(other) {} // copy 
    Str(Moveable& other) { data.swap(other.ref.data); } // move 

    Moveable Move() 
    { 
     return Moveable(*this); 
    } 

    std::string data; 
}; 

Str test() 
{ 
    Str s; 
    //... 
    return s.Move(); // no allocation, even without NRVO 
} 

Vì vậy, ... Có tất cả điều này có ý nghĩa, hoặc có một số vấn đề nghiêm trọng mà tôi đang thiếu? (Tôi không chắc chắn nếu không có vấn đề suốt đời ví dụ). Có lẽ bạn đã thấy ý tưởng như vậy trong một thư viện (sách, bài báo ...), và có thể cho tôi một tham chiếu đến nó?

EDIT: Như @rstevens nhận thấy, mã này là MSVC cụ thể và sẽ không biên dịch theo g ++ mà không thích không const tạm thời. Điều này một vấn đề, nhưng chúng ta hãy chỉ giả định việc triển khai này là cụ thể cho MSVC.

+0

Tôi không chắc chắn những gì bạn đang yêu cầu. Bạn chỉ cần sửa mã của mình? Bạn nói nó làm chính xác những gì bạn muốn nhưng - theo như tôi thấy - nó không nên biên dịch. –

+2

Bạn đã kiểm tra xem chuỗi của bạn có COW hay không. Nếu như vậy sẽ có ít phân bổ bộ nhớ bổ sung. Ngoài ra một số triển khai của std :: string sẽ đặt chuỗi trong đối tượng (khi chuỗi ngắn) thay vì cấp phát bộ nhớ cho nó. Nếu khô héo trong số này là sự thật, nỗ lực tối ưu hóa của bạn có thể làm tăng chi phí thay vì giảm chi phí. –

+0

@Charles: Mã có để giải thích những gì tôi đang cố gắng đạt được, và câu hỏi là nếu tôi thấy nó đúng và nếu đã có một số triển khai tốt về điều đó. –

Trả lời

4

Việc triển khai tăng sử dụng di chuyển ngữ nghĩa thi đua nội bộ cho các thư viện như Boost.Thread. Bạn có thể muốn xem xét việc thực hiện và làm một cái gì đó tương tự.

Chỉnh sửa: thực sự có sự phát triển tích cực của thư viện Boost.Move, vì vậy bạn đã có thể bắt đầu sử dụng nó.

0

Bạn đã thực sự xác định rằng trả về theo giá trị là một vấn đề hiệu suất trong ứng dụng của bạn? Điều đó có vẻ giống như cách đơn giản nhất/dễ nhất để đi và khi bạn nâng cấp lên trình biên dịch hiện đại hơn, bạn có thể sử dụng tham chiếu rvalue.

Tôi không thể trả lời câu hỏi liên quan đến thứ tự hủy của s và tham chiếu của Movable. Bạn có thể, cho trình biên dịch của bạn, đặt mã trong các nhà xây dựng khác nhau và destructors để xem thứ tự là gì.Ngay cả khi nó có vẻ ok tôi vẫn sẽ xem xét việc sử dụng một trong những mô hình bình thường bạn vạch ra mặc dù chỉ để ngăn chặn sự nhầm lẫn người đọc và có thể phá vỡ trên một trình biên dịch thay thế.

+1

Nó không chỉ là một câu hỏi tối ưu hóa với tôi, vì nó ảnh hưởng đến việc sử dụng thông thường - trừ khi các nhà phát triển biết rằng lợi nhuận theo giá trị là rẻ, họ sẽ cố gắng tránh làm điều này. Mọi người vẫn cố gắng viết mã phần nào tối ưu, ngay cả khi bạn nói rằng tối ưu hóa sớm là ác. –

1

Bạn đã kiểm tra mã này trên g ++ chưa?

Vì bạn gọi Str (Movable &) với đối tượng tạm thời (đối tượng được trả về bởi s.Move())!

Đây không phải là tiêu chuẩn tuân thủ và không được hỗ trợ bởi g ++. Nó được hỗ trợ bởi MSVC! (MS gọi đây là một tính năng ...).

+0

Bạn nói đúng, sẽ không biên dịch theo g ++, tôi đã cập nhật câu hỏi. Một cái gì đó khác nhau có thể có thể được thực hiện cho g + +, nhưng tôi quan tâm nhiều hơn để biết nếu một cái gì đó * tương tự * được sử dụng ở đâu đó, không chính xác thực hiện mẫu của tôi. –

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