簡體   English   中英

使用包含shared_ptr的對象的const正確性

[英]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
    //...
}

不,沒有...但是你可以使用COWdeep-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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM