Dưới đây là một đoạn trích từ mục 56 của cuốn sách "C++ Gotchas":C++ sao chép cấu trúc xây dựng-and-assign câu hỏi
Nó không phải là hiếm để thấy một khởi đơn giản của một đối tượng Y viết bất kỳ của ba cách khác nhau, như thể chúng tương đương nhau.
Y a(1066);
Y b = Y(1066);
Y c = 1066;
Trong thực tế, cả ba khởi tạo có thể sẽ dẫn đến trong mã cùng một đối tượng là tạo ra, nhưng chúng không tương đương. Việc khởi tạo một cái được gọi là khởi tạo trực tiếp và nó thực hiện chính xác những gì người ta có thể mong đợi. Việc khởi tạo được thực hiện thông qua một yêu cầu trực tiếp của Y :: Y (int).
Các khởi tạo của b và c là phức tạp hơn. Trên thực tế, chúng quá phức tạp. Đây là cả hai bản sao khởi tạo. Trong trường hợp của việc khởi tạo b, chúng tôi đang yêu cầu việc tạo tạm thời vô danh loại Y, được khởi tạo với giá trị 1066. Sau đó chúng tôi sử dụng thông tin ẩn danh tạm thời này làm tham số cho bản sao hàm tạo cho lớp Y để khởi tạo b. Cuối cùng, chúng tôi gọi hàm hủy là tạm thời ẩn danh.
Để kiểm tra điều này, tôi đã làm một lớp đơn giản với thành viên dữ liệu (chương trình được đính kèm ở cuối) và kết quả thật đáng ngạc nhiên. Dường như đối với trường hợp của c, đối tượng được xây dựng bởi hàm tạo bản sao chứ không phải như được đề xuất trong cuốn sách.
Có ai biết liệu tiêu chuẩn ngôn ngữ đã thay đổi hay đơn giản chỉ là tính năng tối ưu hóa của trình biên dịch? Tôi đã sử dụng Visual Studio 2008.
mẫu Mã số:
#include <iostream>
class Widget
{
std::string name;
public:
// Constructor
Widget(std::string n) { name=n; std::cout << "Constructing Widget " << this->name << std::endl; }
// Copy constructor
Widget (const Widget& rhs) { std::cout << "Copy constructing Widget from " << rhs.name << std::endl; }
// Assignment operator
Widget& operator=(const Widget& rhs) { std::cout << "Assigning Widget from " << rhs.name << " to " << this->name << std::endl; return *this; }
};
int main(void)
{
// construct
Widget a("a");
// copy construct
Widget b(a);
// construct and assign
Widget c("c");
c = a;
// copy construct!
Widget d = a;
// construct!
Widget e = "e";
// construct and assign
Widget f = Widget("f");
return 0;
}
Output:
Constructing Widget a
Copy constructing Widget from a
Constructing Widget c
Assigning Widget from a to c
Copy constructing Widget from a
Constructing Widget e
Constructing Widget f
Copy constructing Widget from f
Tôi đã rất ngạc nhiên nhất bởi kết quả xây dựng d và e. Để được chính xác, tôi đã mong đợi một đối tượng trống được tạo ra, và sau đó một đối tượng được tạo ra và gán cho đối tượng trống. Trong thực tế, các đối tượng đã được tạo bởi trình tạo bản sao.
"Trong trường hợp khởi tạo b, chúng tôi yêu cầu tạo tạm thời ẩn danh loại Y, được khởi tạo với giá trị 1066" ... và giống như trong khởi tạo của c, nó khó xem hơn tạm thời. –
Lưu ý rằng 'Y c = 1006' là không thể nếu hàm tạo của bạn được khai báo là' tường minh' ... như bất kỳ hàm tạo tham số nào, hầu hết thời gian. –
Matthieu, vâng tôi đồng ý với những gì bạn nói và tôi luôn làm điều đó khi lập trình. Điểm của bạn cũng được đề cập trong cuốn sách "Hiệu quả hơn C++" nếu tôi nhớ chính xác. – Andy