使用包含shared_ptr的对象的const正确性

时间:2013-04-30 08:23:15

标签: c++ const shared-ptr

考虑对象:

class Obj
{
    public:
        Obj() : val(new int(1)) {}
        int& get() {return *val;}
        const int& get() const {return *val;}

    private:
        std::shared_ptr<int> val;
};

正如预期的那样,当构造对象并创建副本时,它们都可以通过Obj公开的shared_ptr修改相同的值。

    Obj nonconst1;
    Obj nonconst2(nonconst1);
    nonconst2.get() = 2;
    cout << nonconst1.get() << ", " << nonconst2.get() << endl;

也可以从非const中复制构造一个const Obj对象,这似乎做了正确的事情,因为它允许读取但不写入值 - 正如预期的那样,以下代码导致编译错误:

    const Obj const1(nonconst1);
    const1.get() = 3;

然而,可以从const one复制构造一个非const Obj,然后允许修改该值。

    Obj nonconst3(const1);
    nonconst3.get() = 3;

对我而言,这感觉不太正确。

有没有办法防止这种行为,同时仍允许复制构造函数工作?在我的实际用例中,我仍然希望Obd的std容器成为可能。

6 个答案:

答案 0 :(得分:2)

“对我来说这感觉不是const-correct”但它是:你只是在非const get上调用非const Obj方法。没错。

如果你真的需要你所追求的行为,你可以使用类似const代理的东西来Obj但是你的客户当然必须能够处理它:

class Obj
{
  //...
  //original class definition goes here
  //...
  friend class ConstObj;
};  

class ConstObj
{
  public:
    ConstObj( const Obj& v ) : val( v.val ) {}
    const int& get() const { return *val; }

   private:
    std::shared_ptr<int> val;
};

//usage:
class WorkingWithObj
{
public:
  WorkingWithObj();
  Obj DoSomethingYieldingNonConstObj();
  ConstObj DoSomethingYieldingConstObj();
};

WorkingWithObj w;
Obj nonconst( w.DoSomethingYieldingNonConstObj() );
nonconst.get() = 3;

ConstObj veryconst( nonconst );
veryconst.get() = 3; //compiler error

ConstObj alsoconst( w.DoSomethingYieldingConstObj() );
alsoconst.get() = 3; //compiler error

答案 1 :(得分:1)

不,没有,除非您想存储shared_ptr<const int>,在这种情况下, nobody 可以将其作为非const访问。

答案 2 :(得分:1)

这不会破坏const的正确性。 val指向的整数对象是一个独特的对象,它不是原始对象专有的。修改其值不会影响Obj个对象的状态。

答案 3 :(得分:1)

  

有没有办法防止这种行为,同时仍允许复制构造函数工作?在我的实际用例中,我仍然希望Obd的std容器成为可能。

您可以指定一个不同的复制构造函数来复制const对象 - 这意味着您可以例如避免复制共享指针,而是使用NULL指针创建非const对象,或者您可以对指向的数字执行深层复制。我做这种事情时非常谨慎 - 根据复制变量的常量得到不同的行为很奇怪 - 我担心它会让你很难推理你的程序行为。但是,您必须选择某些行为或接受当前行为,因为std::vector<>有时会创建副本 - 您不能简单地将其保留为未定义。

答案 4 :(得分:0)

手动实现Obj的拷贝构造函数,然后应该复制共享指针的内容。这样可以避免通过const1修改nonconst3的内容,因为它们指向不同的int实例。

但是,您希望避免Obj非const 实例的深层副本(这里没有问题并打算重用旧的共享指针)。为此,您必须提供const和非const复制构造函数,并仅在const one中复制:

class Obj
{
  public:
    //...
    Obj(Obj &o) : val(o.val) {}                            // not a deep copy
    Obj(const Obj &o) : val(std::make_shared(o.get())) {}  // deep copy
    //...
}

答案 5 :(得分:0)

不,没有...但你可以使用COWdeep-copy指针,当你可以写value时(在非const getter中)。

或者,您可以写两个copy-ctorsref执行浅拷贝,cref执行深拷贝。

   A(A& obj) : pointer(obj.pointer) {}
   A(const A& obj) : pointer(new int(*obj.pointer)) {}
相关问题