繁体   English   中英

创建 boost::shared_ptr 的深层副本

[英]Create Deep copy of boost::shared_ptr

我有两个 shared_ptr 向量;

typedef boost::shared_ptr <A> someptr;
std::vector<someptr>src;
std::vector<someptr>dest;

如果我使用 dest=src 复制,两个向量元素共享相同的 memory 位置,这会增加指针的引用计数。它们都指向公共位置,一个向量元素的任何变化都会影响另一个。我知道这是浅拷贝,这是预期的行为。

但是,如果我想为具有不同 memory 位置的 dest 向量元素创建一个深拷贝,我该怎么办?如何实现?

升压是否有 function 来实现这一目标?

当然。 最简单的:

#include <vector>
#include <memory>

struct T {};

int main() {
    std::vector<T> a{100};
    auto b = a; // deep copy all T
}

当然,您拥有shared_ptr是有原因的。 例如,当对象不可移动和/或运行时多态时。


输入指针容器

Boost Pointer Container 满足了这一需求。 它允许您自定义应该克隆元素的方式(参见例如boost::ptr_vector 如何深度复制底层对象?文档)。

简单示例: Live On Coliru

#include <vector>
#include <memory>
#include <boost/ptr_container/ptr_vector.hpp>
#include <iostream>

struct Base {
  virtual ~Base() = default; // runtime polymorphic
  virtual char const* foo() const = 0;
};

struct T : Base {
  virtual char const* foo() const override { return "T"; }
};
struct U : Base {
  virtual char const* foo() const override { return "U"; }
};

static inline Base* new_clone(Base const& obj) {
    if (auto* p = dynamic_cast<T const*>(&obj))
        return new T{*p};
    if (auto* p = dynamic_cast<U const*>(&obj))
        return new U{*p};
    return nullptr;
}

int main() {
    boost::ptr_vector<Base> a;
    std::generate_n(std::back_inserter(a), 5, [] { return new T{}; });
    // polymorphic
    a.insert(a.begin()+2, new U{});

    auto b = a; // deep copy all elements, derived from Base

    // not sharing the instances:
    assert(&a.front() != &b.front());

    std::cout << "\na:";
    for (auto& el : a) std::cout << " " << el.foo(); 

    std::cout << "\nb:";
    for (auto& el : b) std::cout << " " << el.foo(); 
}

印刷

a: T T U T T T
b: T T U T T T

std::vector<unique_ptr>

这在概念上是相似的,但需要您做更多的工作:

住在科利鲁

#include <algorithm>
#include <vector>
#include <memory>
#include <iostream>
#include <cassert>

struct Base {
  virtual ~Base() = default; // runtime polymorphic
  virtual char const* foo() const = 0;
};

struct T : Base {
  virtual char const* foo() const override { return "T"; }
};
struct U : Base {
  virtual char const* foo() const override { return "U"; }
};

struct Cloner {
    using Ptr = std::unique_ptr<Base>;
    Ptr operator()(Ptr const& pb) const {
        if (auto* p = dynamic_cast<T const*>(pb.get()))
            return std::make_unique<T>(*p);
        if (auto* p = dynamic_cast<U const*>(pb.get()))
            return std::make_unique<U>(*p);
        return nullptr;
    }
};

int main() {
    std::vector<std::unique_ptr<Base> > a;
    a.push_back(std::make_unique<T>());
    a.push_back(std::make_unique<U>());
    a.push_back(std::make_unique<T>());

    std::vector<std::unique_ptr<Base> > b;

    // deep copy all elements, derived from Base
    Cloner clone;
    std::transform(begin(a), end(a), back_inserter(b), clone);

    // not sharing the instances:
    assert(&*a.front() != &*b.front());

    std::cout << "\na:";
    for (auto& p : a) std::cout << " " << p->foo(); 

    std::cout << "\nb:";
    for (auto& p : b) std::cout << " " << p->foo(); 
}

印刷:

a: T U T
b: T U T

vector<unique_ptr>但“更容易”?

如果您愿意,可以使用一些“魔术”来简化:

  • 使用升压范围

    住在科利鲁

     // deep copy all elements, derived from Base auto b = boost::copy_range<upvec>(a | transformed(Cloner{}));
  • 使用标准范围 (c++20)

    改用 Ranges v3,因为to_vector尚未标准化(还)

    Live On 编译器资源管理器

     // deep copy all elements, derived from Base auto b = ranges::to_vector(a | ranges::views::transform(Cloner{}));

全自动: Boost PolyContainer

这不保留顺序,但它的优点是您不必提出克隆逻辑,并且您可以按类型进行智能迭代等:

住在科利鲁

#include <boost/poly_collection/base_collection.hpp>
#include <memory>
#include <iostream>
#include <cassert>

struct Base {
  virtual ~Base() = default; // runtime polymorphic
  virtual char const* foo() const = 0;
};

struct T : Base {
  virtual char const* foo() const override { return "T"; }
};
struct U : Base {
  virtual char const* foo() const override { return "U"; }
};

int main() {
    using C = boost::poly_collection::base_collection<Base>;
    
    C a;
    a.insert(T{});
    a.insert(U{});
    a.insert(T{});

    // deep copy all elements, derived from Base
    auto b = a;

    // not sharing the instances:
    assert(&*a.begin() != &*b.begin());

    std::cout << "\na:";
    for (auto& p : a) std::cout << " " << p.foo(); 

    std::cout << "\nb:";
    for (auto& p : b) std::cout << " " << p.foo(); 
}

印刷

a: U T T
b: U T T

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM