2011-07-28 20 views
9

Trong Scott Meyers của Effective C++, mục 18 Hãy giao diện dễ sử dụng một cách chính xác và khó sử dụng không đúng cách, ông đề cập đến shared_ptr null:Tại sao người ta cần một shared_ptr null và làm thế nào nó có thể được sử dụng?

std::tr1::shared_ptr<Investment> pInv(static_cast<Investment*>(0), getRidOfInvestment) 

và một toán tử gán vogue

pInv = ...  //make retVal point to the correct object 

Trong trường hợp nào người ta có thể cần phải tạo ra một shared_ptr null và làm bài tập sau? Tại sao không chỉ tạo shared_ptr bất cứ khi nào bạn có tài nguyên (con trỏ thô)?

Kể từ khi Scott Meyers không cho thấy sự phân công hoàn thành trong ví dụ trước, tôi nghĩ điều hành assign của shared_ptr bị quá tải mà ta có thể làm điều này:

pInv = new Investment; // pInv will take charge of the pointer 
          // but meanwhile keep the delete function it already had 

Nhưng tôi đã cố gắng với tăng 's thực hiện nó không hoạt động theo cách này. Vậy ý nghĩa của việc có null shared_ptr là gì?

Tôi gần như chắc chắn rằng tôi đang thiếu điều gì đó ở đây, một người nào đó giúp tôi ra khỏi nó xin vui lòng.

ps. thêm về khởi tạo và phân công một shared_ptr

#include <boost/shared_ptr.hpp> 

int main(int argc, char *argv[]) 
{ 
    boost::shared_ptr<int> ptr1(new int); 
    boost::shared_ptr<int> ptr2; 
    ptr2.reset(new int); 
    boost::shared_ptr<int> ptr3 = new int; 

    return 0; 
} 

ví dụ này không thể được biên soạn bởi g ++ (Ubuntu/Linaro 4.5.2-8ubuntu4) 4.5.2 và thúc đẩy mới nhất:

sptr.cpp: In function ‘int main(int, char**)’: 
sptr.cpp:8:39: error: conversion from ‘int*’ to non-scalar type ‘boost::shared_ptr<int>’ requested 
+0

Tôi cố gắng để con số nó ra ở đây: http://ideone.com/BUjOwZ. Tôi không thể đưa ra lời giải thích. –

+0

Như những người khác đã chỉ ra, có rất nhiều lý do để cần một shared_ptr null, giống như bạn có null con trỏ thô. Nhưng bí ẩn thực sự là lý do tại sao Scott cảm thấy cần thiết cho nó để có một deleter tùy chỉnh. –

Trả lời

19

Không cần sử dụng hack đó để có được giá trị rỗng (trống) shared_ptr. Đơn giản chỉ cần sử dụng constructor mặc định:

std::shared_ptr<Investment> pInv; // starts null 

Để gán một con trỏ đến một shared_ptr, hoặc làm điều đó vào thời điểm xây dựng:

std::shared_ptr<Investment> pInt(new Investment); 
// not allowed due to explicit annotation on constructor: 
// std::shared_ptr<Investment> pInt = new Investment; 

Hoặc sử dụng .reset() chức năng:

pInt.reset(new Investment); 

Có thể rằng tác giả của bài viết đó có thể có ý định cung cấp một deleter tùy chỉnh (getRidOfInvestment). Tuy nhiên, chức năng deleter được đặt lại khi số .reset() được gọi, hoặc khi không thì con trỏ bên trong bị thay đổi. Nếu bạn muốn có một deleter tùy chỉnh, bạn phải vượt qua nó để .reset() khi tạo ra các shared_ptr.

Một mẫu bạn có thể muốn sử dụng để làm cho điều này hết sức rõ ràng hơn là một chức năng tạo tùy chỉnh:

class Investment { 
protected: 
    Investment(); 
    // ... 
public: 
    static shared_ptr<Investment> create(); 
}; 

shared_ptr<Investment> Investment::create() { 
    return shared_ptr<Investment>(new Investment, getRidOfInvestment); 
} 

Sau đó:

shared_ptr<Investment> pInv = Investment::create(); 

Điều này đảm bảo bạn sẽ luôn luôn có chức năng destructor đúng gắn liền với số shared_ptr được tạo từ Investment s.

+0

Ví dụ givien trong quetion, lý do cho con trỏ null trong lời gọi hàm tạo là sử dụng một deleter tùy chỉnh. Các nhà xây dựng cho con trỏ thông minh không có một phiên bản mà chỉ mất deleter tùy chỉnh, do đó sự cần thiết cho "hack". – diverscuba23

+0

Điểm tốt, tôi đã thêm một chút để thảo luận về điều đó. – bdonlan

+1

"std :: shared_ptr pInt = new Investment;" không thể được biên dịch – zhanwu

2

Có rất nhiều lý do khiến bạn có thể thích các đối tượng được cấu hình mặc định.Đầu tiên và trước hết bạn muốn con trỏ thông minh giống như con trỏ thô, và vì bạn có thể nói int * p; (và nhận con trỏ chưa được xác định, chưa được khởi tạo), bạn cũng có thể nói shared_ptr<int> p; và nhận con trỏ không điểm bất cứ nơi nào (nhưng bạn có thể kiểm tra nó với !).

Một trong những lý do thuyết phục nhất có thể là bạn có thể tạo các thùng chứa với shared_ptr s và bạn có thể lấp đầy các thùng chứa mà không cần chỉ định điểm ngay tại đó.

6

Đó là lý do tương tự để có con trỏ thô không có giá trị - ví dụ:

nói rằng bạn có:

typedef std::tr1::shared_ptr<Investment> InvestmentPtr; 
map<key,InvestmentPtr> portfolio; 
... 
get(mykey) { 
    iterator it = portfolio.find(mykey); 
    if (it == portfolio.end()) 
    return InvestmentPtr(); 
    else 
    return it->second; 
    } 
} 

này cho phép bạn làm:

InvestmentPtr p = get(key); 
if (p) ... 
Các vấn đề liên quan