7

考虑对象:

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 Obj从非 const 之一复制构造一个对象,这似乎是正确的,因为它允许读取但不能写入该值 - 正如预期的那样,以下代码会导致编译错误:

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

但是,可以从 const 复制构造非 const Obj,然后允许修改该值。

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

对我来说,这感觉不正确。

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

4

6 回答 6

2

“对我来说,这感觉不正确”但它是:您只是在非 constget上调用非 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
于 2013-04-30T08:35:12.940 回答
1

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

于 2013-04-30T08:27:15.123 回答
1

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

于 2013-04-30T08:37:32.553 回答
1

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

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

于 2013-04-30T08:42:32.540 回答
0

手动实现一个复制构造函数,Obj然后应该复制共享指针的内容。这避免了修改const1via的内容nonconst3,因为它们指向不同的 int 实例。

但是,您希望避免对非 const实例进行深拷贝Obj(这没问题,并且打算重用旧的共享指针)。为此,您必须同时提供 const 和非 const 复制构造函数,并且仅在 const 中复制:

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
    //...
}
于 2013-04-30T08:34:23.433 回答
0

不,没有...但是您可以使用COW,deep-copy指针,当您可以写入时value(在非常量 getter 中)。

或者,你可以写两个copy-ctorsref做浅拷贝,cref做深拷贝)。

   A(A& obj) : pointer(obj.pointer) {}
   A(const A& obj) : pointer(new int(*obj.pointer)) {}
于 2013-04-30T08:35:41.910 回答