2012-05-26 62 views
22

Trong một số nơi tôi đã nhìn thấy chữ ký đề nghị của sao chép và di chuyển nhà xây dựng đưa ra như:Một nhà xây dựng di chuyển có tham chiếu const hoặc tham chiếu rvalue không const?

struct T 
{ 
    T(); 
    T(const T& other); 
    T(T&& other); 
}; 

Trường hợp nhà xây dựng bản sao phải mất một tham chiếu const, và các nhà xây dựng chuyển mất một tài liệu tham khảo rvalue không const.

Theo như tôi có thể thấy mặc dù, điều này ngăn cản tôi lợi dụng ngữ nghĩa di chuyển khi trở về đối tượng const từ một chức năng, chẳng hạn như trong trường hợp dưới đây:

T generate_t() 
{ 
    const T t; 
    return t; 
} 

kiểm tra này với VC11 Beta, T ' s constructor được gọi là, và không phải là nhà xây dựng di chuyển. Ngay cả khi sử dụng return std::move(t); thì hàm tạo bản sao vẫn được gọi.

Tôi có thể thấy điều này có ý nghĩa như thế nào, vì t là const nên không được liên kết với T&&. Sử dụng const T&& trong chữ ký hàm khởi tạo hoạt động tốt, và có ý nghĩa, nhưng sau đó bạn có vấn đề bởi vì other là const, bạn không thể null thành viên của nó nếu chúng cần được rỗng - nó sẽ chỉ hoạt động khi tất cả các thành viên là vô hướng hoặc di chuyển các hàm tạo bằng chữ ký đúng. Có vẻ như cách duy nhất để đảm bảo rằng hàm tạo di chuyển được gọi trong trường hợp tổng quát là đã làm cho t không phải là const ở vị trí đầu tiên, nhưng tôi không thích làm điều đó - những thứ liên kết là hình thức tốt và tôi sẽ không mong đợi khách hàng của T biết rằng họ phải đi ngược lại biểu mẫu đó để tăng hiệu suất.

Vì vậy, tôi đoán câu hỏi của tôi là gấp đôi; đầu tiên, nên một nhà xây dựng di chuyển mất một const hoặc tham chiếu rvalue không const? Và thứ hai: tôi có đúng trong dòng lý luận này không? Rằng tôi nên ngừng trả lại những thứ là const?

+2

Vâng, tôi nghĩ rằng các trường hợp sử dụng trả về const thời gian là hơi nhỏ. Nếu bạn khai báo trước, thì vì bạn muốn làm một số thứ với nó trước khi trở về. Nếu không, thì một 'return T()' đơn giản sẽ làm. Mặc dù tôi vẫn có thể thấy một số trường hợp sử dụng nhất định, tôi nghĩ chúng hiếm. Và tất nhiên, một tham chiếu rvalue mà từ đó bạn không thể ăn cắp tài nguyên không thực sự có giá trị nào so với một tham chiếu lvalue. Tuy nhiên, câu hỏi đặt câu hỏi. –

+1

Nhân tiện, mã này có đủ điều kiện cho NRVO không? Vì vậy, những gì "nên" xảy ra là đối tượng 'const'' t' được xây dựng vào cùng một vị trí với giá trị trả về không const. Sau đó, nếu cần thiết mà giá trị trả về không const * có thể * được di chuyển bởi người gọi thông qua hàm tạo non-const (hoặc một toán tử gán di chuyển). Tuy nhiên, trong trường hợp xây dựng, nó sẽ lại đủ điều kiện cho phép sao chép bản sao và 't' có thể được xây dựng trực tiếp vào bất kỳ thứ gì đang được khởi tạo bằng cách sử dụng lệnh gọi' generate_t() '. Điều gì cản trở VC11 thực hiện tối ưu hóa này? –

+1

_consting mọi thứ là tốt form_ không nếu bạn muốn sửa đổi chúng, ví dụ: bằng cách di chuyển từ họ. –

Trả lời

18

Nó phải là tham chiếu không phải là const rvalue.

Nếu một đối tượng được đặt trong bộ nhớ chỉ đọc, bạn không thể lấy cắp tài nguyên từ nó, ngay cả khi thời gian hoạt động chính thức của nó kết thúc ngay. Các đối tượng được tạo dưới dạng const trong C++ được phép sống trong bộ nhớ chỉ đọc (sử dụng const_cast để cố gắng thay đổi kết quả trong hành vi không xác định).

+2

Rất có thể đây không phải là trường hợp. Một đối tượng mà từ đó bạn có thể di chuyển dường như chỉ ra rằng nó quản lý tài nguyên, vì vậy bộ nhớ phải ghi được khi đối tượng được xây dựng, và nó có thể có một destructor giải phóng các tài nguyên đó, vì vậy một lần nữa, nó sẽ phải ghi trong quá trình hủy. Tôi nghi ngờ rằng trình biên dịch sẽ tạo mã để quản lý đánh dấu trang bộ nhớ dưới dạng chỉ đọc sau khi xây dựng và đánh dấu nó là có thể ghi trước khi hủy (và chỉ đọc lại sau khi hủy hoàn tất vì hầu hết có thể đối tượng không đơn độc trong trang bộ nhớ đó. .) Điều đó đang được nói +1 –

+0

@David: "Tôi nghi ngờ rằng ..." - đúng, nhưng nó có thể là tính năng hữu ích trong chế độ gỡ lỗi, đặc biệt. khi sửa mã không chính xác const. Tôi nghĩ điểm quan trọng là mặc dù điều này không thực sự xảy ra, nhưng thực tế là nó giải thích lý do tại sao bạn không thể sửa đổi các đối tượng const trước destructor của chúng (và đặc biệt là không thể chuyển từ chúng một cách hiệu quả) . –

+0

@SteveJessop: Đó là lý do cho +1: cho dù đối tượng ở trong bộ nhớ chỉ đọc hay không thay đổi thực tế là việc di chuyển ra khỏi một đối tượng không đổi là phá vỡ hợp đồng: bạn đang sửa đổi một cái gì đó mà bạn đã hứa không chạm. –

8

Một hàm tạo di chuyển thường lấy tham chiếu không phải const.

Nếu có thể di chuyển từ một đối tượng const, nó thường ngụ ý rằng việc sao chép một đối tượng giống như là "di chuyển" có hiệu quả như thế nào. Tại thời điểm này thường không có lợi khi có một hàm khởi tạo.

Bạn cũng chính xác rằng nếu bạn có một biến mà bạn có khả năng muốn di chuyển từ đó, nó sẽ cần phải không phải là const.

Vì tôi hiểu đây là lý do khiến Scott Meyers đã thay đổi lời khuyên của mình về việc trả về các đối tượng thuộc loại lớp theo giá trị từ các hàm cho C++ 11. Trả về các đối tượng theo giá trị đủ điều kiện const sẽ ngăn không chủ ý sửa đổi một đối tượng tạm thời nhưng nó cũng ức chế chuyển động từ giá trị trả về.

5

Một nhà xây dựng di chuyển có tham chiếu const hoặc tham chiếu rvalue không const không?

Phải mất tham chiếu không phải giá trị rvalue.Các tham chiếu rvalue trước hết không có ý nghĩa trong các dạng const của chúng đơn giản chỉ vì bạn muốn thay đổi chúng (theo cách nào đó, bạn muốn "di chuyển" chúng, bạn muốn nội bộ của chúng cho chính mình).

Ngoài ra, chúng được thiết kế để sử dụng mà không có const và tôi tin rằng chỉ sử dụng cho tham chiếu const rvalue là một cái gì đó rất rất phức tạp mà Scott Meyers đã đề cập trong số this nói chuyện.

Tôi có đúng trong dòng lập luận này không? Rằng tôi nên ngừng trả lại những thứ là const?

Đây là một câu hỏi quá chung chung để tôi trả lời. Trong bối cảnh này, tôi nghĩ đáng nói rằng có chức năng std::forward sẽ bảo toàn cả rvalue-ness và lvalue-ness cũng như const-ness và nó cũng sẽ tránh tạo tạm thời như một hàm bình thường nếu bạn trả về nó.

này trở về cũng sẽ gây ra rvalue tham khảo là "nham nhở" vào tham khảo giá trị trái và bạn thường không muốn điều đó, vì thế, chuyển tiếp hoàn hảo với các chức năng nói trên giải quyết vấn đề này.

Điều đó đang được nói, tôi đề nghị bạn chỉ cần xem qua bài nói chuyện mà tôi đã đăng liên kết tới.

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