![](/img/trans.png)
[英]Deep copy of std::stack< boost::shared_ptr<T> >
[英]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
尚未标准化(还)
// deep copy all elements, derived from Base auto b = ranges::to_vector(a | ranges::views::transform(Cloner{}));
这不保留顺序,但它的优点是您不必提出克隆逻辑,并且您可以按类型进行智能迭代等:
#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.