我有shared_ptr的两个 vector ;
typedef boost::shared_ptr <A> someptr;
std::vector<someptr>src;
std::vector<someptr>dest;
如果我使用dest = src复制,这两个 vector 元素共享相同的内存位置,这会增加指针的ref计数。它们都指向相同的位置,并且一个 vector 元素的任何变化都会影响另一个。我知道这是浅拷贝,这是预期的行为。但是,如果我想为具有不同存储位置的dest vector 元素创建深拷贝,该怎么办?如何实现呢?
Boost是否具有实现此目的的功能?
最佳答案
当然。最简单的:
#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满足了这一需求。它允许您自定义克隆元素的方式(请参见How does boost::ptr_vector deep copy the underlying objects?或the docs)。
简单示例: 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>
这在概念上类似,但是需要您做更多的工作:Live On Coliru
#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>
但是“更轻松”?如果您愿意,可以使用一些“魔术”使之更简单:
Live On Coliru
// deep copy all elements, derived from Base
auto b = boost::copy_range<upvec>(a | transformed(Cloner{}));
改用Ranges v3,因为
to_vector
尚未标准化(尚未)Live On Compiler Explorer
// deep copy all elements, derived from Base
auto b = ranges::to_vector(a | ranges::views::transform(Cloner{}));
全自动:Boost PolyContainer
这不会保留顺序,但是它的优点是您不必提出克隆逻辑,并且可以按类型等进行智能迭代:
Live On Coliru
#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
关于c++ - 创建boost::shared_ptr的深层拷贝,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/62596539/