考虑对象:
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容器成为可能。
答案 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)
不,没有...但你可以使用COW
,deep-copy
指针,当你可以写value
时(在非const getter中)。
或者,您可以写两个copy-ctors
(ref
执行浅拷贝,cref
执行深拷贝。
A(A& obj) : pointer(obj.pointer) {}
A(const A& obj) : pointer(new int(*obj.pointer)) {}