智能指针的 const 正确性
Posted
技术标签:
【中文标题】智能指针的 const 正确性【英文标题】:const correctness with smart pointers 【发布时间】:2012-01-09 19:02:45 【问题描述】:我试图更好地理解const-correctness
是如何工作的,更具体地说,在处理其成员基于containers
和smart pointers
的类时。
我猜const-correctness
属性是相同的,无论类成员如何。但是,由于我很难清楚地了解发生了什么,
我决定征求你的意见。
所以,这里是上下文。我有一个ShapeContainer
类,它有一个智能指针向量作为私有类成员。
Shape
类是抽象的,具有以下虚函数 virtual float doSomething();
,然后由其派生类重新定义。请注意,它是一个非常量类函数。
相关部分代码如下:
class ShapeContainer
public:
typedef std::shared_ptr<Shape> ShapePtr;
typedef std::vector<ShapePtr> ShapePtrContainer;
// .......
const ShapePtr & operator[]( int ) const return m_vect[index]; ; // const version
// ShapePtr & operator[]( int ) return m_vect[index]; ; // non-const version
// .......
private:
ShapePtrContainer m_vect;
;
class Shape
public:
// ...
virtual float doSomething() = 0;
;
这是我的问题。
第一季度。为什么我可以通过以下方式调用doSomething()
函数:int index = 0; float tmp = container1[index]->doSomething();
(具有ShapeContainer container1=createBasicShapes();
)?
据我了解,在调用const ShapePtr operator[] const
函数后,我们将得到一个const
指向Shape
对象的指针,但是doSomething()
是虚拟的
函数是不是 const。那么,对 const 对象的引用如何调用非 const 函数呢?
第二季度。通过调用 doSomething()
函数,如前所述 (float tmp =container1[index]->doSomething();
)和通过添加 operator[]
的 non-const
版本,此 latter
然后调用重载版本而不是const-version
。为什么会这样?
现在,我不再拥有 ShapeContainer
类,而是创建了一个名为 ShapeContainerInfo
的新类,它仍然有一个 vector
,但属于中间 ShapeInfo
类(它有一个智能指针作为类成员)。
class ShapeContainerInfo
public:
typedef std::vector<ShapeInfo> ShapeContainer;
const ShapeInfo & operator []( int index) const return m_vect[index]; ;
// ShapeInfo & operator []( int index) return m_vect[index]; ; // non-const version
private:
ShapeContainer m_vect;
;
class ShapeInfo
public:
typedef std::shared_ptr<Shape> ShapePtr;
// ...
float doSomething() return m_ShapePtr->doSomething(); ;
private:
ShapePtr m_ShapePtr;
int m_nID;
;
第三季度。当我调用float tmp = container2[i].doSomething();
时,我收到以下编译器错误:error C2662: 'ShapeInfo::doSomething' : cannot convert 'this' pointer from 'const ShapeInfo' to 'ShapeInfo &'
。
但是,当我添加重载operator []
的non-const
版本时,编译器错误消失了。那么,为什么我真的需要 non-const operator[]
来代替 ShapeContainerInfo
而不是 ShapeContainer
?
第四季度。如果ShapeContainerInfo
的m_vect
private
成员现在设置为public
成员并且仅 定义了operator[]
的常量版本(不是non-const
之一),那么没有编译器错误消息。为什么这个?例如将m_vect
设置为公共类成员后:float tmp = info.m_vect[i].doSomething();
Q5。如何正确定义ShapeInfo
和ShapeContainerInfo
类,这样我只需要定义operator[]
的const-version
并且仍然能够调用float doSomething()
函数?
对整个示例代码感兴趣的人,请找到它here。 澄清,建议总是受欢迎的:-) 谢谢!
【问题讨论】:
【参考方案1】:Q1:shared_ptr 是 const,这并不意味着指向的对象是 const。为此,您需要shared_ptr<const Shape>
。
Q2:由于你的 ShapeContainer 不是 const,所以 non-const 函数更匹配,所以调用它而不是 const 版本。
Q3:vector 将其 constness 传播到其元素。 shared_ptr 没有。这与数组和原始指针的行为是一致的。 const 数组的元素是 const。 const 指针所指向的东西(必然)不是 const。
Q4:你是说这不会产生错误吗?
ShapeContainerInfo info;
info[0].doSomething();
请澄清,因为那应该是一个错误。
Q4:好的,所以你说这不会产生错误:
ShapeContainerInfo info;
info.m_vect[0].doSomething();
也不应该。向量不是常量。只有在 const 成员函数内部,vector(和所有其他成员)才被视为 const。
Q5:使 m_vect 成为唯一指针的向量。在 const 函数内部,向量本身是 const,唯一指针是 const。但是唯一指针指向的对象是可变的。
举个例子,这个类中的set函数是不合法的:
struct Foo
void set(int index, int value) const
v[index] = value;
std::vector<int> v;
;
但是这个是:
struct Foo
void set(int index, int value) const
*v[index] = value;
std::vector<std::unique_ptr<int>> v;
;
【讨论】:
@本杰明,谢谢。关于您对Q3
的回答,我将std::vector
定义为non-const
,或者在代码中的确切位置,vector
是否被视为const
?你对Q4/Q5
有什么建议吗?
@Tin:由于您的成员函数是 const,因此该类的所有成员在该函数内都被视为 const。我还在分析 Q5。
@本杰明,不是真的,这是我的时候:float tmp = info.m_vect[i].doSomething();在这种情况下,我将 m_vect 设置为公共类成员而不是私有成员,除此之外,我只考虑了 operator[] 的const version
。
@Benjamin,关于Q3
,我在某处读到返回objects by reference
通常不是一个好主意。不幸的是,我没有找到链接。你怎么看这个肯定?此外,关于Q4
,这意味着,由于向量是non-const
,也是它的元素,那么我们可以调用non-const
函数,比如doSomething
,对吧?如果你能帮助Q5
,那就太好了;-)
@Tin: SO cmets 不是讨论的好地方,答案也不是那么简单。如果您想问这个问题,请打开一个新帖子。已添加对 Q5 的回答。以上是关于智能指针的 const 正确性的主要内容,如果未能解决你的问题,请参考以下文章