当然。最简单的:
#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{}));
-
使用标准范围 (c++20)
改用 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{}));
这不保留顺序,但它的优点是你不必想出克隆逻辑,并且可以按类型等进行智能迭代:
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