[英]Const correctness with objects containing 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容器成為可能。
“對我而言,這並不感覺是const-correct”但它是:你只是在非const Obj
上調用非const get
方法。 沒有錯。
如果你真的需要你所追求的行為,你可以使用類似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
不,沒有,除非你想存儲shared_ptr<const int>
,在這種情況下, 沒有人可以作為非const訪問它。
這並沒有打破常規的正確性。 val
指向的整數對象是一個獨特的對象,它不是由原始對象專有。 修改其值不會影響Obj
對象的狀態。
有沒有辦法防止這種行為,同時仍然允許復制構造函數工作? 在我的實際用例中,我仍然希望Obd的std容器成為可能。
您可以指定一個不同的復制構造函數來從const
對象復制 - 這意味着您可以避免復制共享指針,而是使用NULL指針創建非const對象,或者您可以執行指向的深層復制數。 我會非常謹慎地做這種事情 - 根據復制變量的常量來獲取不同的行為很奇怪 - 我擔心這會讓你很難推斷你的程序行為。 但是,您必須選擇一些行為或接受當前行為,因為std::vector<>
有時會創建副本 - 您不能簡單地將其保留為未定義。
手動實現Obj
的復制構造函數,然后復制該共享指針的內容。 這避免了修改的內容const1
通過nonconst3
,因為它們指向不同INT實例。
但是,您希望避免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
//...
}
不,沒有...但是你可以使用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)) {}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.