2009-03-07 40 views
54

tương đương như sau là gì:Con trỏ NULL với tăng :: shared_ptr?

std::vector<Foo*> vec; 
vec.push_back(NULL); 

khi giao dịch với boost::shared_ptr? Có phải mã sau không?

std::vector< boost::shared_ptr<Foo> > vec; 
vec.push_back(boost::shared_ptr<Foo>()); 

Lưu ý: Tôi có thể đẩy lùi nhiều đối tượng như vậy. Tôi có nên khai báo một đối tượng tĩnh nullPtr tĩnh ở đâu đó không? Bằng cách đó, chỉ một trong số chúng sẽ phải được xây dựng:

boost::shared_ptr<Foo> nullPtr; 
+4

tin tốt từ tiêu chuẩn C++ tiếp theo: ở đó, bạn có thể viết "vec.emplace_back();" và có thêm một con trỏ null: –

+7

Hãy xem xét sử dụng 'boost :: ptr_vector' mà đòi hỏi ít chi phí hơn. – Philipp

Trả lời

0

Có, khai báo một con trỏ rỗng tĩnh tổng thể.

4

Bạn có thể khai báo toàn cầu nullPtr cho shared_ptr<Foo>. Nhưng nếu bạn gây ô nhiễm không gian tên chung, bạn sẽ gọi toàn cầu là gì nullPtr cho shared_ptr<Bar>?

Thông thường tôi khai báo ptr rỗng là tĩnh trong lớp con trỏ.

#include <boost\shared_ptr.hpp> 

class Foo; // forward decl 
typedef boost::shared_ptr<Foo> FooPtr; 
class Foo 
{ 
public: 
    static FooPtr Null; 
} 
... 
// define static in cpp file 
FooPtr Foo::Null; 
... 
// use Foo Null 
vec.push_back(Foo::Null); 

Bằng cách đó, mỗi lớp có một Null tĩnh.

+1

Bạn có thể nhận được cú pháp tự nhiên hơn bằng cách sử dụng toán tử chuyển đổi khuôn mẫu trên biến toàn cầu. Xem câu trả lời của tôi ... :) –

52

Đề xuất của bạn (gọi số shared_ptr<T> hàm tạo không có đối số) là chính xác. (Gọi hàm khởi tạo với giá trị 0 là tương đương.) Tôi không nghĩ rằng điều này sẽ chậm hơn gọi số vec.push_back() với số sẵn có shared_ptr<T>, vì yêu cầu xây dựng trong cả hai trường hợp (xây dựng trực tiếp hoặc sao chép-xây dựng).

Nhưng nếu bạn muốn cú pháp "đẹp hơn", bạn có thể thử đoạn mã sau:

class { 
public: 
    template<typename T> 
    operator shared_ptr<T>() { return shared_ptr<T>(); } 
} nullPtr; 

này khai báo một đối tượng toàn cầu duy nhất nullPtr, cho phép cú pháp tự nhiên sau đây:

shared_ptr<int> pi(new int(42)); 
shared_ptr<SomeArbitraryType> psat(new SomeArbitraryType("foonly")); 

... 

pi = nullPtr; 
psat = nullPtr; 

Note nếu bạn sử dụng điều này trong nhiều đơn vị dịch (tệp nguồn), bạn sẽ cần đặt tên cho lớp (ví dụ: _shared_null_ptr_type), di chuyển định nghĩa của đối tượng nullPtr sang tệp .cpp riêng biệt và thêm extern khai báo trong t ông tập tin tiêu đề nơi lớp được xác định.

+0

dude ý tưởng hay. tôi đã phải +1 rằng: p nhưng lưu ý câu trả lời ở đây http://stackoverflow.com/questions/395685/how-do-you-choose-between-a-singleton-and-an-unnamed-class/395738# 395738 –

+0

Xin cảm ơn các bạn. :) Nhìn vào bài viết của litb cho thấy rằng lớp thực sự nên được đặt tên mặc dù. –

+0

một số tên ngớ ngẩn: nullPtrT, NullPtrType, nullPtr_t. bất cứ điều gì :) tôi thấy họ thêm một _t khi chỉ có một ví dụ của một cái gì đó (như, nothrow_t và nullptr_t). –

17

Vâng, điều này là hợp pháp:

shared_ptr<Foo> foo; /* don't assign */ 

Và trong trạng thái này, nó không trỏ đến bất cứ điều gì.Bạn thậm chí có thể kiểm tra khách sạn này:

if (foo) { 
    // it points to something 
} else { 
    // no it doesn't 
} 

Vậy tại sao không làm điều này:

std::vector < shared_ptr<Foo> > vec; 
vec.push_back (shared_ptr<Foo>); // push an unassigned one 
1

Dưới đây là một cái gì đó mà tôi nghĩ là một chút đơn giản hơn và làm việc tốt

(hãy nhớ rằng typedef là của bạn bạn bè):

#include <cstdlib> 
#include <vector> 
#include <iostream> 
#include <boost/shared_ptr.hpp> 

typedef boost::shared_ptr< std::vector<char> > CharVecHandle; 

inline CharVecHandle newCharVec(std::vector<char>::size_type size) { 
    return CharVecHandle(new std::vector<char>(size)); 
} 

inline CharVecHandle newCharVec(void) { 
    return CharVecHandle(); 
} 

int main (void) 
{ 
    CharVecHandle cvh = newCharVec(); 

    if (cvh == NULL) 
     std::cout << "It's NULL" << std::endl; 
    else 
     std::cout << "It's not NULL" << std::endl; 

    std::vector<CharVecHandle> cvh_vec; 

    cvh_vec.push_back(newCharVec(64)); 
    cvh_vec.push_back(newCharVec()); 

    // or call the NULL constructor directly 
    cvh_vec.push_back(CharVecHandle()); 

    return EXIT_SUCCESS; 
} 
+0

Chắc chắn, một 'typedef' là đẹp hơn để xem xét hơn' boost :: shared_ptr ', và OP dường như chỉ quan tâm đến một kiểu duy nhất 'Foo', trong trường hợp đó' typedef' rất phù hợp. Nếu bạn muốn tránh sự gia tăng của 'typedef' cho các kiểu con trỏ thông minh khác nhau, cách tiếp cận của tôi là tốt hơn tôi nghĩ. Bạn không chắc chắn những gì bạn đang cố gắng để chứng minh với các hàm 'newCharVec()' của bạn, bạn có thể giải thích? –

+0

@j_random_hacker: Mục đích của các hàm 'newCharVec' giống như hàm typedef, sự tiện lợi và nhất quán. Ít ký tự hơn để loại và nhất quán trong việc tạo các đối tượng thực và các đối tượng NULL. Vấn đề là, ngay cả khi tôi đang sử dụng các phương pháp mẫu, tôi vẫn có thể sẽ tạo ra một typedef. Đến từ một nền 'C' bất cứ khi nào tôi thấy một kiểu khai báo quá phức tạp, bản năng đầu tiên của tôi là đánh máy nó. Việc tính đến điều đó, tôi không chắc chắn nếu thực sự có lý do khách quan để chọn phương pháp này hay phương pháp khác, nó có thể là vấn đề về phong cách hay sở thích cá nhân. –

+0

Vâng, một lý do để thích cách tiếp cận của tôi là, bởi vì 'nullPtr' của tôi là kiểu bất khả tri, nó sẽ làm việc trong các mẫu hàm khi thao tác các biến có kiểu không xác định, trong khi đó bạn sẽ không. Ví dụ. Tôi có thể viết một mẫu chức năng 'mẫu push_a_null_ptr (vector > & v) {v.push_back (nullPtr); } ', sẽ làm việc cho tất cả các loại' T'. Tôi thừa nhận nó không phải là một mặt tích cực lớn, nhưng tôi không thấy bất kỳ nhược điểm nào. –

9

Trong C++ 0x, bạn chỉ cần chuyển đổi từ nullptr đến std::shared_ptr:

std::vector< boost::shared_ptr<Foo> > vec; 
vec.push_back(nullptr); 
Các vấn đề liên quan