簡體   English   中英

通過unique_ptr或值傳遞對象以及如何實現

[英]Passing object by unique_ptr or by value and how to implement

我有一種情況,我不確定是否應該使用unique_ptr或按值傳遞Object。

假設我有A類,其向量為B類,而C類也有向量,為B類。 每次我在C類的Vector中添加B對象時,都應將其從C類的Vector中刪除,反之亦然。 當銷毀對象C時,應將B Vector類中的所有對象添加到A類的B vector中

class B {
public:
    B();
    virtual ~B();
};

class A {
    C & c;
    std::vector<B> bs;
public:
    A(C & c ): c(c){};
    virtual ~A();
    void add(B b){
        bs.push_back(b);
        c.remove(b);
    }
    void remove(B b){
        bs.erase(std::remove(bs.begin(), bs.end(), b), bs.end());
    }
};

class C {
public:
     A & a;
    std::vector<B> bs;
    C(A & a): a(a) {

    };
    virtual ~C(){
        for (B b : bs) {
                a.add(b);
                remove(b);
            }
    }

    void add(B b){
        bs.push_back(b);
        a.remove(b);
    }
    void remove(B b){
        bs.erase(std::remove(bs.begin(), bs.end(), b), bs.end());
    }
};

我的問題:

  1. 在這種情況下使用指針更好嗎? 我應該始終為B具有唯一的對象! 換句話說,如果兩個b對象的內容不同,則它們仍將不同,因為內存中的地址不同。
  2. 我想在C ++ 11中借助smart_pointers編寫此代碼! 哪種類型為shared_ptrunique_ptr更好? AB對象永遠不會由兩個對象擁有,並且它始終只有一個所有者,因此我猜unique_ptr更好,但我不確定。
  3. 如何使用unique_ptr編寫以上代碼?
  1. 如果復制構造B的成本很高,那么(智能)指針可能是一個好主意(重新設計應用程序邏輯可能是另一種解決方案),

  2. 如果我理解正確,給定的B實例始終由單個所有者( AC )操縱。 因此, std::unique_ptr是一個合理的選擇,

  3. 嘗試以下實現。 我沒有編譯它,但我想您會明白的:)

class B {
public:
    B();
    virtual ~B();
};

class A {
    C & c;
    std::vector<std::unique_ptr<B>> bs;
public:
    A(C & c ): c(c){};
    virtual ~A();
    // http://herbsutter.com/2013/06/05/gotw-91-solution-smart-pointer-parameters/
    // (c) Passing unique_ptr by value means "sink."
    void add(std::unique_ptr<B> b){
        c.remove(b);               // release the poiner from the other container
        bs.emplace_back(b.get());  // emplace the pointer in the new one
        b.release();               // emplacement successful. release the pointer
    }
    // http://herbsutter.com/2013/06/05/gotw-91-solution-smart-pointer-parameters/
    // (d) Passing unique_ptr by reference is for in/out unique_ptr parameters.
    void remove(std::unique_ptr<B>& b){
        // @todo check that ther returned pointer is != bs.end()
        std::find(bs.begin(), bs.end(), b)->release();             // first release the pointer
        bs.erase(std::remove(bs.begin(), bs.end(), b), bs.end());  // then destroy its owner
    }
};

class C {
public:
    A & a;
    std::vector<std::unique_ptr<B>> bs;
    C(A & a): a(a) {

    };
    virtual ~C(){
        for (auto&& b : bs) {
            a.add(b);
            // a is going to call this->remove()...
            // unless calling this->remove() from "a"
            // while this is being destroyed is Undefined Behavior (tm)
            // I'm not sure :)
        }
    }
    // http://herbsutter.com/2013/06/05/gotw-91-solution-smart-pointer-parameters/
    // (c) Passing unique_ptr by value means "sink."
    void add(std::unique_ptr<B> b){
        c.remove(b);               // release the poiner from the other container
        bs.emplace_back(b.get());  // emplace the pointer in the new one
        b.release();               // emplacement successful. release the pointer
    }
    // http://herbsutter.com/2013/06/05/gotw-91-solution-smart-pointer-parameters/
    // (d) Passing unique_ptr by reference is for in/out unique_ptr parameters.
    void remove(std::unique_ptr<B>& b){
        // @todo check that ther returned pointer is != bs.end()
        std::find(bs.begin(), bs.end(), b)->release();             // first release the pointer
        bs.erase(std::remove(bs.begin(), bs.end(), b), bs.end());  // then destroy its owner
    }
};

如果需要的話,我只會使用unique_ptr 您可能希望將B設置為僅移動類型(例如unique_ptr )以限制所有權。

如果B移動成本很高,或者防止B的復制不切實際,請使用unique_ptr但要注意,您隨后要為動態內存分配付費。

在受代碼啟發的示例中,這是如何使用僅移動B的方法。 如果您使用unique_ptr則它應該完全相同:

struct B {
    B();
    B(B&&) = default;                 // Explicitly default the 
    B& operator=(B&&) = default;      // move functions.

    B(const B&) = delete;             // Delete copy functions - Not strictly 
    B& operator=(const B&) = delete;  // necessary but just to be explicit.
};

struct A {
    std::vector<B> bs;
    void add(B b){
        bs.push_back(std::move(b));
    }
    B remove(std::vector<B>::iterator itr){
        B tmp = std::move(*itr);
        bs.erase(itr);
        return tmp;
    }  
};

struct C {
    A& a;
    std::vector<B> bs;
    C(A& a) : a(a) {}

    ~C(){
        for (auto& b : bs) {
            a.add(std::move(b));
        }
    }  // bs will be deleted now anyway, no need to remove the dead objects

    void add(B b){
        bs.push_back(std::move(b));
    }
    B remove(std::vector<B>::iterator itr){
        auto tmp = std::move(*itr);
        bs.erase(itr);
        return tmp;
    }
};

int main() {
    A a;
    C c(a);
    a.add(B());
    auto tmp = a.remove(a.bs.begin());
    c.add(std::move(tmp));
}

現場演示。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

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