2012-07-27 26 views
11

Có thể viết một con trỏ thông minh phân bổ chính đối tượng trong hàm tạo của nó - thay vì nhà phát triển phải gọi new? Nói cách khác, thay vì viết:Tại sao một con trỏ thông minh không thể gọi hàm new() cho tôi trong hàm tạo của nó?

std::unique_ptr<myClass> my_ptr(new myClass(arg1, arg2))

... người ta có thể viết:

std::smarter_ptr<myClass> my_ptr(arg1, arg2)

là cú pháp ngôn ngữ có khả năng thể hiện này? Điều này có được mong muốn không? Hiếm? Tôi đang nghĩ đến đặc biệt bảo vệ chống lại sai lầm này (mà tôi đã thực hiện bản thân mình, tất nhiên):

myFunction(std::unique_ptr<myClass>(new myClass()), std::unique_ptr<myClass>(new myClass()))

... mà có nguy cơ bị rò rỉ bất cứ đối tượng được phân bổ đầu tiên nếu việc phân bổ thứ hai xảy ra và ném trước khi đối tượng đầu tiên được giữ an toàn trong con trỏ thông minh của nó. Nhưng một con trỏ thông minh hơn có thực sự làm việc này an toàn không?

+2

@Joe: Đó là mối quan tâm; hoàn toàn có thể cho mã được tạo ra để thực thi hai biểu thức 'mới' trước khi sử dụng kết quả để khởi tạo một con trỏ thông minh; trong trường hợp đó bạn sẽ bị rò rỉ nếu cái thứ hai ném. –

+2

@Joe: Bạn sai rồi. 'tmp1 = new myClass(); tmp2 = new myClass(); arg1 = std :: unique_ptr (tmp1); arg2 = std :: unique_ptr (tmp2); myFunction (arg1, arg2); 'là một trật tự thực thi pháp lý hoàn hảo. –

+1

Đủ công bằng, tôi đã tìm cách chứng minh bản thân mình không chính xác. Cảm ơn. – Joe

Trả lời

17

Xem xét triển khai make_shared(). Nó làm điều này phân bổ một đối tượng mới và tạo ra một shared_ptr trong số đó.

+0

Tuyệt vời - thậm chí còn tiết kiệm được phân bổ. Cảm ơn. :-) – bythescruff

2

Điều này là mới có thể với C++ 11 được thêm perfect forwarding và mẫu variadic.

2

Về cơ bản, vấn đề đó là cần thiết std::findstd::find_if. Bạn không thể phân biệt ctor này với các ctors hiện tại của shared_ptr trong trường hợp new myClass(arg1). Số lượng đối số bằng nhau và arg1 có thể có bất kỳ loại nào.

Vì vậy, bạn cần một cái tên khác, và đó là make_shared

+0

Điều này có thể dễ dàng giải được với các loại thẻ, như 'shared_ptr (std :: inplace_args, args ...)', cũng là những gì tiêu chuẩn làm cho việc chuyển các đối số cấp phát cho các hàm variadic nhất định. – Xeo

+0

@ Xeo, đúng vậy, vì vậy 'make_shared' là không cần thiết, nó có thể đã được thực hiện như OP gợi ý, nhưng' make_shared (args ...) 'ít được gõ anyway :) –

+0

@Xeo: Thật vậy. Có nhiều giải pháp khả thi và C++ không hoàn toàn nhất quán. – MSalters

11

Nói chung, điều này không thể được thực hiện với nhà xây dựng một con trỏ thông minh của; sẽ có một sự mơ hồ về việc liệu một đối số con trỏ có nên được sử dụng để initalise con trỏ thông minh hay chuyển tiếp để tạo một đối tượng mới.

Nó có thể được thực hiện với một chức năng nhà máy, ví dụ:

template <typename T, typename... Args> 
std::unique_ptr<T> make_unique(Args&&... args) { 
    return std::unique_ptr<T>(new T(std::forward<Args>(args)...)); 
} 

Nếu bạn đang sử dụng std::shared_ptr, sau đó bạn có thể sử dụng std::make_shared. Điều này cũng mang lại lợi thế là chỉ yêu cầu phân bổ bộ nhớ, trong đó std::shared_ptr<T>(new T) sẽ yêu cầu một đối tượng và một giây cho số tham chiếu được chia sẻ.

+0

Chắc chắn sự mơ hồ sẽ chỉ tồn tại nếu tính năng được thêm vào các con trỏ thông minh hiện có, phải không? Tôi vẫn còn tò mò về lý do tại sao họ không được thực hiện như 'make_shared()' để bắt đầu; có một sự bất đối xứng làm tôi bị lỗi khi có con trỏ thông minh gọi là 'xóa' nhưng phải gọi chính nó là 'mới'. – bythescruff

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