2013-02-28 46 views
6

Vì vậy, tôi đã xem c + + video trên youtube ngày hôm qua và đi qua một trong đó là về C++ - 11 rvalue tham chiếu và di chuyển ngữ nghĩa. Tôi nghĩ rằng tôi hiểu khái niệm theo nghĩa rộng, nhưng hôm nay khi tôi đã trải qua mã của tôi với TA, ông hỏi tại sao tôi không cho chúng tôi một tham chiếu (như std::pair<HostName, IPAddress>& p) trong đoạn mã dưới đây. Tôi đã không nghĩ về nó ở tất cả trong trường hợp này, nhưng khi ông hỏi tôi nhớ video nói "Trong C++ - 11, bạn thường nên sử dụng đi qua giá trị."Tham chiếu C++ rvalue và di chuyển ngữ nghĩa

Câu hỏi của tôi là như vậy: Trong mã bên dưới, liệu std::pair<HostName, IPAddress> p có thể tắt tốt hơn như std::pair<HostName, IPAddress>& p hay không? Sẽ di chuyển ngữ nghĩa được sử dụng và nó sẽ tạo sự khác biệt?

IPAddress NameServer::lookup(const HostName& host) const { 
    auto it = std::find_if(vec.begin(), vec.end(), 
         [host] (std::pair<HostName, IPAddress> p) { 
     return p.first == host; 
    }); 
    ... 
} 

Trả lời

10

Trong trường hợp này, bạn nên vượt qua tham chiếu const. Việc truyền theo giá trị có ý nghĩa khi bạn cuối cùng muốn tạo bản sao hoặc di chuyển, của giá trị được truyền; nếu bạn không muốn sao chép cũng như không di chuyển và đặc biệt nếu bạn muốn chỉ quan sát, bạn nên chuyển qua (const) tham chiếu.

Ở đây, thuộc tính lambda của bạn không cần tạo bất kỳ bản sao nào của cặp nhận được trong đầu vào: do đó, không có lý do nào để chuyển giá trị (cũng không phải chụp bởi vaue).

IPAddress NameServer::lookup(const HostName& host) const { 
    auto it = std::find_if(vec.begin(), vec.end(), 
     [&host] (std::pair<HostName, IPAddress> const& p) { 
    // ^^^^^         ^^^^^^ 
     return p.first == host; 
    }); 
    ... 
} 

xem xét, thay vào đó, trường hợp này (điển hình C++ 03 code):

struct A 
{ 
    A(string const& s) : _s(s) { } 
private: 
    string _s; 
}; 

Trong C++ 11, kể từ khi bạn có ngữ nghĩa di chuyển, chứ không phải đi qua s bằng cách tham chiếu liên tục bạn có thể chỉ cần chuyển theo giá trị và di chuyển nó vào biến thành viên:

struct A 
{ 
    A(string s) : _s(move(s)) { } 
private: 
    string _s; 
}; 

Điều này có ý nghĩa bởi vì chúng tôi luôn tạo ra một bản sao của giá trị được chuyển.

Như một cách chính xác chỉ ra bởi Benjamin Lindley trong các ý kiến, nếu điều này là chấp nhận được đối với bạn, bạn thể ghi quá tải của các nhà xây dựng trên đó lấy lập luận của mình bằng cách tham khảo:

struct A 
{ 
    A(string const& s) : _s(s) { } // 1 copy 
    A(string&& s) : _s(move(s)) { } // 1 move 
private: 
    string _s; 
}; 

Phiên bản trên cho phép thực hiện chỉ một bản sao cho giá trị, và một chuyển cho giá trị, trong khi phiên bản đi theo giá trị luôn luôn thực hiện thêm một bước di chuyển. Do đó, giải pháp này có thể thích hợp hơn nếu di chuyển là một hoạt động tốn kém cho các loại đối số của bạn (đây không phải là trường hợp cho string, nhưng có thể là trường hợp đối với các loại khác).

Tuy nhiên, làm như vậy có thể cồng kềnh nếu hàm của bạn mất một số đối số. Để giảm nỗ lực, bạn có thể viết một mẫu chức năng duy nhất lấy tham chiếu phổ dụng và chuyển tiếp hoàn hảo các đối số của nó. This Q&A on StackOverflow có liên quan đến chủ đề.

+1

Tôi tự hỏi nếu lambda không nên nắm bắt bằng cách tham chiếu ở đây? – juanchopanza

+0

@juanchopanza: Vâng, chắc chắn: bỏ qua điều đó. Cảm ơn –

+0

+1, tốt hơn! – juanchopanza

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