2013-08-09 15 views
8

Tôi đã một hàm trả về một vector hoặc thiết lập:Làm thế nào để tránh được những bản sao khi tôi trở

set<int> foo() { 
    set<int> bar; 
    // create and massage bar 
    return bar; 
} 

set<int> afoo = foo(); 

Trong trường hợp này, tôi có thể tạo một không gian bộ nhớ tạm thời chức năng foo(), và sau đó gán nó đến afoo bằng cách sao chép. Tôi thực sự muốn tránh bản sao này, bất kỳ cách nào dễ dàng tôi có thể làm điều này trong C++ 11? Tôi nghĩ điều này liên quan đến điều rvalue. OK, cập nhật cho câu hỏi: Nếu tôi sẽ trả về một đối tượng được xác định bởi bản thân mình, không phải là vectơ hoặc thiết lập, điều đó có nghĩa là tôi nên định nghĩa một hàm tạo di chuyển? như sau:

class value_to_return { 
    value_to_return (value_to_return && other) { 
    // how to write it here? I think std::move is supposed to be used? 
    } 
} 

THanks !!!

+4

Những gì bạn hiện có sẽ không tạo bản sao nào trong C++ 11. Nó có thể làm cho di chuyển, nhưng ngay cả những người gần như chắc chắn sẽ được tối ưu hóa bằng [N/RVO] (http://en.wikipedia.org/wiki/Return_value_optimization). –

+11

"cách tránh sao chép khi tôi trở lại" - biên dịch với trình biên dịch được phát hành cách đây không quá 10 năm. –

+0

Tôi rất cám dỗ để downvote tất cả các câu trả lời mà không đề cập đến di chuyển/rvalues. –

Trả lời

5

Khám phá return value optimization. Một trình biên dịch hiện đại sẽ tối ưu hóa tình huống này, và trong các tình huống đơn giản như thế này, sẽ không có bản sao nào được thực hiện trên bất kỳ trình biên dịch chính nào.

Về nguyên tắc, bạn cũng có thể tạo đối tượng của mình bên ngoài hàm, sau đó gọi hàm và chuyển đối tượng đến hàm đó bằng tham chiếu. Đó sẽ là cách cũ để tránh một bản sao, nhưng nó là không cần thiết và không mong muốn bây giờ.

-3

Tôi thường làm việc xung quanh này bằng cách có chức năng chữ ký như

void foo(set<int> *x) 

Chỉ cần vượt qua nó bằng cách tham chiếu hoặc các tùy chọn khác đã được đề cập trong nhận xét.

Chỉnh sửa: Tôi đã thay đổi loại đối số để minh họa rằng x có thể thay đổi.

 set<int> s; 
     foo(&s); 

Điều này chỉ được ưu tiên khi bạn có trình biên dịch cũ. Tôi cho rằng đó có thể là trường hợp với một số dự án.

Và, điều tốt hơn cần làm là sử dụng di chuyển ngữ nghĩa với C++ 11. Hoặc tiếp tục trả lại container và nhìn vào RVO trong các trình biên dịch hiện đại.

+0

Tôi đang bỏ phiếu này vì đây là câu trả lời * duy nhất * đề xuất truyền trong thông số đầu ra. Một câu trả lời hoàn hảo sẽ bao gồm RVO và di chuyển các nhà xây dựng là tốt. –

+8

Hầu như bị cám dỗ bỏ phiếu nó _down_ để đề xuất các tham số đầu ra. –

+0

@EdS .: Thông số đầu ra là khủng khiếp. – Puppy

18

Modem C++ biên dịch sẽ thực hiện: cho một loại T:

  • Nếu T có một bản sao tiếp cận hoặc di chuyển constructor, trình biên dịch có thể chọn để bõ mẫu âm chót bản sao. Đây là cái gọi là (tên) return value optimization (RVO), được chỉ định ngay cả trước C++ 11 và là được hỗ trợ bởi hầu hết các trình biên dịch.
  • Nếu không, nếu T có số move constructor, T sẽ được di chuyển (Vì C++ 11).
  • Nếu không, nếu T có một hàm tạo bản sao, T sẽ được sao chép.
  • Nếu không, lỗi biên dịch sẽ được phát ra.
+0

Hãy sửa tôi nếu tôi sai, nhưng AFAIK trả lại giá trị tối ưu hóa chỉ hoạt động khi bạn xây dựng đối tượng trực tiếp trong câu lệnh return như sau: 'return (set ) (...);' Một trình biên dịch thông minh có thể chuyển đổi mã trong câu hỏi vào mẫu này, nhưng đối với các chức năng phức tạp hơn, tôi sẽ tưởng tượng rằng nó sẽ không hoạt động. – cmaster

+0

@cmaster, trong trường hợp OP, RVO cũng sẽ được áp dụng. Đọc liên kết wiki trong câu trả lời của tôi về RVO. :) – billz

+0

@cmaster: Tối ưu hóa một bản sao trong trường hợp trả về biến được đặt tên thường được gọi là NRVO, được đặt tên là tối ưu hóa giá trị trả lại và đã được thực hiện nhiều năm trước bởi hầu hết các trình biên dịch. – JohannesD