2010-01-17 186 views
37

我有几个容器中的一类,对于包含 shared_ptr的对居住在堆中的对象实例,载体或地图。C++智能指针const正确性

例如

template <typename T> 
class MyExample 
{ 
public: 

private: 
vector<tr1::shared_ptr<T> > vec; 
map<tr1::shared_ptr<T> , int> h; 
}; 

我想有这个类,有时会返回shared_ptrs 为const对象(通过shared_ptr<const T>)的公共接口,有时shared_ptr<T>其中 我允许呼叫者突变的对象。我想要逻辑常量的正确性,所以如果我将 方法标记为const,它不能更改堆上的对象。

问题:

1)我由tr1::shared_ptr<const T>tr1::shared_ptr<T>互换性混淆。 当有人经过一个shared_ptr<const T> shared_ptr的进级,做我把它存为载体内shared_ptr<T>shared_ptr<const T>和地图或修改我的地图,矢量类型(例如insert_elemeent(shared_ptr<const T> OBJ)?

2)它是更好地实例化类如下:MyExample<const int>?这似乎 不适当的限制,因为我永远不会返回shared_ptr<int>

回答

3

有一点要明白的是,:

tr1::shared_ptr<const T>被模仿的T const *即它所指向的是常量的功能,但指针本身是没有的。

所以你可以给你的共享指针分配一个新的值,但我希望你不能使用取消引用的shared_ptr作为l值。

+1

“l值”。一个l值不需要赋值! – curiousguy 2011-12-15 06:36:30

5

如果有人通过你一个shared_ptr<const T>你永远不应该能够修改T。当然,在技术上可以将const T转换为T,但这打破了制作Tconst的意图。所以如果你希望人们能够添加对象到你的班级,他们应该给你shared_ptr<T>shared_ptr<const T>。当你从班上回来的东西你不想修改,那就是当你使用shared_ptr<const T>

shared_ptr<T>可以自动转换(没有明确的转换)为shared_ptr<const T>,但不能反过来。它可以帮助你(无论如何你都应该这样做)自由使用const方法。当您定义类方法const时,编译器将不允许您修改任何数据成员或返回除const T之外的任何内容。因此,使用这些方法将帮助您确保您没有忘记某些内容,并且可以帮助您的班级的用户了解该方法的意图。 (例如:virtual shared_ptr<const T> myGetSharedPtr(int index) const;

你在你的第二个说法是正确的,你可能不希望实例化类为<const T>,因为你将永远不能修改任何你T S的。

34

shared_ptr<T> and shared_ptr<const T> are not interchangable。它有一种方法 - shared_ptr<T>可转换为shared_ptr<const T>但不是相反。

观察:

// f.cpp 

#include <memory> 

int main() 
{ 
    using namespace std; 

    shared_ptr<int> pint(new int(4)); // normal shared_ptr 
    shared_ptr<const int> pcint = pint; // shared_ptr<const T> from shared_ptr<T> 
    shared_ptr<int> pint2 = pcint; // error! comment out to compile 
} 

编译通过

CL/EHSC f.cpp

您也可以根据常量性重载函数。你可以结合做这两个事实来做你想做的事情。

至于你的第二个问题,MyExample<int>可能比MyExample<const int>更有意义。

11

我建议以下methotology:

template <typename T> 
class MyExample 
{ 
    private: 
    vector<shared_ptr<T> > data; 

    public: 
    shared_ptr<const T> get(int idx) const 
    { 
     return data[idx]; 
    } 
    shared_ptr<T> get(int idx) 
    { 
     return data[idx]; 
    } 
    void add(shared_ptr<T> value) 
    { 
     data.push_back(value); 
    } 
}; 

这保证常量,正确性。就像你看到的add()方法不使用< const T>但是< T>因为你打算这个类存储Ts而不是const Ts。但是,当访问它时,你会返回< const T>这是没有问题的,因为shared_ptr < T>可以很容易地转换为shared_ptr < const T>。并且sice中的get()方法都会将shared_ptr的副本返回到内部存储中,调用者不会意外更改内部指针指向的对象。这完全可以与非智能指针变体相媲美:

template <typename T> 
class MyExamplePtr 
{ 
    private: 
    vector<T *> data; 

    public: 
    const T *get(int idx) const 
    { 
     return data[idx]; 
    } 
    T *get(int idx) 
    { 
     return data[idx]; 
    } 
    void add(T *value) 
    { 
     data.push_back(value); 
    } 
}; 
+0

难道不应该''shared_ptr '可以很容易地被转换成 到shared_ptr '而不是其他方式吗? – user231536 2010-01-17 16:13:02

+0

当只返回一个简单的成员时,那么超载似乎不是什么大不了的事情。但是如果你从'vector'返回'shared_ptr' - 你必须计算哪一个是正确的。你如何避免代码重复? – thomthom 2013-12-05 23:03:19