2010-01-26 38 views
17

Trong C++ 11, chúng ta có thể có được một sự gia tăng hiệu quả bằng cách sử dụng std::move khi chúng ta muốn di chuyển (triệt tiêu copy) giá trị vào một container:C++ "di chuyển từ" container

SomeExpensiveType x = /* ... */; 
vec.push_back(std::move(x)); 

Nhưng tôi không thể tìm mọi thứ theo cách khác. Ý của tôi là gì đó như sau:

SomeExpensiveType x = vec.back(); // copy! 
vec.pop_back(); // argh 

Điều này thường xuyên hơn (bản sao) trên bộ điều hợp như stack. Có thể có nội dung như thế này:

Để tránh sao chép? Và điều này đã tồn tại? Tôi không thể tìm thấy bất cứ điều gì như thế trong n3000.

Tôi có cảm giác mình đang thiếu một cái gì đó đau đớn rõ ràng (như sự thiếu thốn của nó), vì vậy tôi chuẩn bị cho "ru dum". : 3

+0

Phương pháp di chuyển có những biến nào nằm ngoài phạm vi? Ví dụ, nếu tôi tạo một đối tượng, thêm nó vào một thùng chứa thành viên, thì đối tượng đó nằm ngoài phạm vi ... Vì không có bản sao nào được tạo ra, là đối tượng trong thùng chứa thành viên vẫn được định nghĩa? – Polaris878

+0

Có, nó đã được chuyển vào thùng chứa. Bạn sẽ muốn tham khảo google rvalue nếu bạn không chắc chắn cách chúng hoạt động. – GManNickG

+0

cảm ơn ngọt ngào ... Tôi sẽ phải đào sâu vào điều này một số lol. Tại mệnh giá có vẻ như điều này sẽ gây ra vấn đề. – Polaris878

Trả lời

15

tôi có thể tổng sai ở đây, nhưng không phải là những gì bạn muốn chỉ

SomeExpensiveType x = std::move(vec.back()); vec.pop_back(); 

Giả sử SomeExpensiveType có một constructor di chuyển. (và rõ ràng là đúng cho trường hợp của bạn)

+0

Tôi nghĩ về điều đó, nhưng tôi cảnh giác về việc di chuyển thứ gì đó từ thùng chứa như thế. Bây giờ tôi nghĩ về nó nhiều hơn, nó có vẻ hoàn toàn hợp pháp ...: | – GManNickG

+0

Hmm. Tôi không chắc đó là chính xác. Chắc chắn vec.back() sẽ phải có ngữ nghĩa di chuyển, tức là trả lại && – ScaryAardvark

+0

Hãy suy nghĩ về bạn, tôi đã nghĩ về nó nhiều hơn một chút và bạn cũng có thể đúng. – ScaryAardvark

-1

Nói chung đối với các loại đắt tiền, tôi nghĩ bạn muốn đẩy lớp bọc hoặc con trỏ thông minh vào vùng chứa thay thế. Bằng cách này, bạn đang tránh các bản sao đắt tiền và thay vào đó chỉ thực hiện các bản sao giá rẻ của con trỏ thông minh hoặc lớp trình bao bọc. Bạn cũng có thể sử dụng con trỏ thô nếu bạn muốn haha.

class ExpensiveWrapper 
{ 
public: 
    ExpensiveWrapper(ExpensiveClass* in) { mPtr = in; } 

    // copy constructors here.... 

private: 
    ExpensiveWrapper* mPtr; 

}; 
+3

Một điểm của ngữ nghĩa 'di chuyển' là loại bỏ phương thức này. Thùng chứa sẽ chỉ di chuyển nội dung của chúng xung quanh thay vì sao chép chúng. – GManNickG

4

Đối đầy đủ (và bất cứ ai ngại về câu hỏi này mà không có một trình biên dịch C++ 1x), một sự thay thế đó đã tồn tại ngày hôm nay:

SomeExpensiveType x; 
std::swap(x, vec.back()); 
vec.pop_back(); 

Nó chỉ đòi hỏi một sự chuyên môn hóa của std::swap để tồn tại cho loại nguyên tố.

+3

Ngoại trừ không sử dụng std :: swap rõ ràng (vì nó không thể được chuyên biệt đúng cho nhiều loại); sử dụng khai báo sử dụng với cuộc gọi hoán đổi không đủ điều kiện. –

+1

@Roger Pate - hoặc sử dụng 'boost :: swap' để có được điều tương tự. –

+0

Tôi muốn gõ một dòng đơn hơn lo lắng về việc ai sẽ khiếu nại về Boost, vì ai đó chắc chắn sẽ làm. :) –

4
template<class C> 
auto pop_back(C& c) -> typename std::decay<decltype(c.back())>::type 
{ 
    auto value (std::move(c.back())); 
    c.pop_back(); 
    return value; // also uses move semantics, implicitly 
    // RVO still applies to reduce the two moves to one 
} 
+0

Tôi thấy std :: phân rã thích hợp hơn std :: remove_reference. Ví dụ, nó biến một "const MyClass &" thành một "MyClass" (loại bỏ const). – sellibitze

+0

@sellibitze: Bạn nói đúng, điều đó phù hợp hơn; cảm ơn! –

+0

Tôi không chắc chắn 100% nhưng một 'typename' có thể bị thiếu sau khi' -> ' – sellibitze

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