簡體   English   中英

C++:深拷貝菱形指針結構

[英]C++: Deep Copy Diamond Pointer Structure

在我的模擬軟件中,我使用 pybind11 生成對象。 因此,所有對象都存儲在 std::shared_ptr 中,編譯時結構未知。 對於我的模擬的並行化,我需要使用不同的種子運行相同的配置。 我想在 C++ 端的一次調用中實現這些對象的復制。

按照一個最小的例子,我希望a2a的深拷貝,具有菱形結構。

// Type your code here, or load an example.
#include <memory>
#include <map>
#include <iostream>

class C{};
class B{
    public:
    B(std::shared_ptr<C> c):c(c){}
    std::shared_ptr<C> c;
};
class A{
    public:
    A(std::shared_ptr<B> b1, std::shared_ptr<B> b2):b1(b1), b2(b2){}
    std::shared_ptr<B> b1;
    std::shared_ptr<B> b2;
};

auto init(){
    auto c = std::make_shared<C>();
    auto b1 = std::make_shared<B>(c);
    auto b2 = std::make_shared<B>(c);
    auto a = std::make_shared<A>(b1,b2);
    return a;
}


int main(){
    auto a = init();
    auto a2 = a; //deepcopy of a, where b1 and b2 of the copy point to the same object C
}

我想出的唯一解決方案是傳遞一個 map<pointer,shared_ptr>。 如果 shared_ptr 已經被深度復制,這允許查找。 (這里我的打字有一些問題,因為我需要動態地回退類型。這感覺真的很難看,而且很容易出錯。)

不確定我是否理解問題,但似乎您只需要A的復制構造函數:

A(const A& other){
    if (other.b1.get() == other.b2.get()) {
        b1 = std::make_shared<B>(std::make_shared<C>(*other.b1->c.get()));
        b2 = b1;
    } else {
        b1 = std::make_shared<B>(std::make_shared<C>(*other.b1->c.get()));
        b2 = std::make_shared<B>(std::make_shared<C>(*other.b2->c.get()));
    }    
}

請注意,這只檢查other.b1other.b2是否是相同的對象。 當它們是不同的對象但指向同一個C時,它將被復制兩次。 如果要檢查other.b1->cother.b2->c是否相同,則需要相應地修改代碼。

您可以使用std::shared_ptr<void>對所有共享指針進行類型擦除,使用std::static_pointer_cast您的實際類型。

using Seen = std::set<std::shared_ptr<void>>;

template <typename T>
std::shared_ptr<T> deep_copy(std::shared_ptr<T> source, Seen & seen) {
    if (auto it = seen.find(std::static_pointer_cast<void>(source)); it != seen.end()) {
        return std::static_pointer_cast<T>(*it);
    }
    auto dest = make(*source, seen);
    seen.insert(std::static_pointer_cast<void>(dest));
    return dest;
}

然后,您可以編寫采用現有實例和seen映射的構造函數來深度復制成員,允許它們是私有的。

template <typename T>
std::shared_ptr<T> make(const T & source, Seen & seen) {
    return std::make_shared<T>(source, seen);
}    

class C{
    public:
    C(){}
    C(const C &, Seen &){}    
};    
class B{
    std::shared_ptr<C> c;
    public:
    B(std::shared_ptr<C> c):c(c){}
    B(const B & other, Seen & seen):c(deep_copy(other.c, seen)){}
};
class A{
    std::shared_ptr<B> b1;
    std::shared_ptr<B> b2;
    public:
    A(std::shared_ptr<B> b1, std::shared_ptr<B> b2):b1(b1), b2(b2){}
    A(const A & other, Seen & seen):b1(deep_copy(other.b1, seen)), b2(deep_copy(other.b2, seen)){}
};

int main(){
    auto a = init();
    Seen a2_seen;
    auto a2 = deep_copy(a, a2_seen);
}

或者,您可以為每種類型重載make ,如果成員是私有的,則make<T>需要被T加為好友。

std::shared_ptr<C> make(const C &, Seen &) {
    return std::make_shared<C>();
}

std::shared_ptr<B> make(const B & other, Seen & seen) {
    auto c = deep_copy(other.c, seen);
    return std::make_shared<B>(c);
}

std::shared_ptr<A> make(const A & other, Seen & seen) {
    auto b1 = deep_copy(other.b1, seen);
    auto b2 = deep_copy(other.b2, seen);
    return std::make_shared<A>(b1, b2);
}

暫無
暫無

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

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