Tôi đã gặp một số mã khiến tôi kinh hãi. Về cơ bản nó sau mô hình này:C++ Đang xây dựng đối tượng hai lần bằng cách sử dụng vị trí hành vi chưa xác định mới?
class Foo
{
public:
//default constructor
Foo(): x(0), ptr(nullptr)
{
//do nothing
}
//more interesting constructor
Foo(FooInitialiser& init): x(0), ptr(nullptr)
{
x = init.getX();
ptr = new int;
}
~Foo()
{
delete ptr;
}
private:
int x;
int* ptr;
};
void someFunction(FooInitialiser initialiser)
{
int numFoos = MAGIC_NUMBER;
Foo* fooArray = new Foo[numFoos]; //allocate an array of default constructed Foo's
for(int i = 0; i < numFoos; ++i)
{
new(fooArray+ i) Foo(initialiser); //use placement new to initialise
}
//... do stuff
delete[] fooArray;
}
Mã này đã được trong các cơ sở mã trong nhiều năm và nó sẽ có vẻ chưa bao giờ gây ra một vấn đề. Nó rõ ràng là một ý tưởng tồi vì ai đó có thể thay đổi constructor mặc định để phân bổ không mong đợi việc xây dựng thứ hai. Đơn giản chỉ cần thay thế constructor thứ hai bằng một phương thức khởi tạo tương đương có vẻ là điều hợp lý để làm. ví dụ.
void Foo::initialise(FooInitialiser& init)
{
x = init.getX();
ptr = new int;
}
Mặc dù vẫn có thể bị rò rỉ tài nguyên, ít nhất một lập trình viên phòng thủ có thể nghĩ để kiểm tra phân bổ trước theo phương pháp thông thường.
Câu hỏi của tôi là:
Được xây dựng hai lần như hành vi thực sự không xác định này/cấm theo tiêu chuẩn hoặc đơn giản chỉ là một ý tưởng tồi? Nếu hành vi không xác định bạn có thể trích dẫn hoặc chỉ cho tôi đúng nơi để xem trong tiêu chuẩn không?
bạn đã thử valgrind trên mã này chưa? – zoska
Vấn đề chính tôi thấy là 'Foo' không tuân thủ quy tắc của ba - bản sao mặc định-ctor và copy-assignment-operator sẽ không làm điều đúng với' Foo :: ptr'. – cdhowie
@cdhowie Có lẽ chúng ta không nên giả định điều tồi tệ nhất về mã của người khác. Tôi đoán OP đơn giản là cắt mã không cần thiết để đặt câu hỏi. – anatolyg