C++ 创建boost::shared_ptr的深度副本
我有两个共享_ptr向量C++ 创建boost::shared_ptr的深度副本,c++,c++11,boost,shared-ptr,C++,C++11,Boost,Shared Ptr,我有两个共享_ptr向量 typedef boost::shared_ptr <A> someptr; std::vector<someptr>src; std::vector<someptr>dest; typedef boost::sharedptrsomeptr; std::vectorsrc; std::vectordest; 如果我使用dest=src复制,两个向量元素共享相同的内存位置,这会增加指针的引用计数。它们都指向公共位置,并且一个向量元
typedef boost::shared_ptr <A> someptr;
std::vector<someptr>src;
std::vector<someptr>dest;
typedef boost::sharedptrsomeptr;
std::vectorsrc;
std::vectordest;
如果我使用dest=src复制,两个向量元素共享相同的内存位置,这会增加指针的引用计数。它们都指向公共位置,并且一个向量元素的任何更改都会影响另一个。我理解这是一个浅拷贝,这是预期的行为
但是,如果我想为具有不同内存位置的dest向量元素创建一个深度副本,我应该怎么做?如何实现
boost有实现这一点的功能吗?当然。最简单的:
#include <vector>
#include <memory>
struct T {};
int main() {
std::vector<T> a{100};
auto b = a; // deep copy all T
}
印刷品
a: T T U T T T
b: T T U T T T
a: U T T
b: U T T
std::vector
这在概念上是相似的,但需要您做更多的工作:
#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();
}
#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();
}
// deep copy all elements, derived from Base
auto b = boost::copy_range<upvec>(a | transformed(Cloner{}));
// 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();
}
vector
但“更简单”?
如果您愿意,您可以使用一些“魔法”来简化:
- 使用增压范围
#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(); }
#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(); }
// deep copy all elements, derived from Base auto b = boost::copy_range<upvec>(a | transformed(Cloner{}));
// 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(); }
全自动: 这不会保留顺序,但它的优点是您不必提出克隆逻辑,您可以按类型等进行智能迭代:
#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();
}
#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();
}
// deep copy all elements, derived from Base
auto b = boost::copy_range<upvec>(a | transformed(Cloner{}));
// 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
的实例,或者也包含从其派生的类的实例?例如:src包含2个元素。dest是一个新的空向量,需要深度副本。它们没有派生类。For(auto const&p:src)dest.push_back(make_shared(*p))
Eljay的解决方案只有在向量不能包含从A派生的类的情况下才有效。如果可以,您将需要其他内容。使用上面的代码语句会抛出错误:showing cannot convert boost::shared_ptr to(const A&)。充实了三个选项:。只有后者能完全为您完成克隆。非常感谢您共享代码。事实上,我拥有的两个向量对象属于同一个类,其中一个不是从另一个类派生的。每当您以b=a进行复制时,它都会导致浅复制。我需要从a到b的深度复制或按值复制。使用复制构造函数从a(b(*a))复制b,是否抛出错误。您是否可以显示问题(可能通过编辑实时样本?)。我不明白你的意思。在我所有的方法中,复制的向量都是相同的类型,它们的副本都很深,并且它们都编译没有错误。