unique_ptr 的向量,继承?
vector of unique_ptr, inheritance?
假设这段代码:
class Parent {}
class Child : public Parent {}
static std::vector<std::unique_ptr<Child>> Foo();
这个函数有没有更简单的写法:
std::vector<std::unique_ptr<Parent>> Bar() {
auto children = Foo();
std::vector<std::unique_ptr<Parent>> parents;
result.insert(result.end(), std::make_move_iterator(children.begin()),
std::make_move_iterator(children.end()));
return parents;
}
这行不通:
std::vector<std::unique_ptr<Parent>> Bar() {
return Foo(); // Compiler error: cannot convert from vector<...> to vector<...>
}
类型不同。 Foo()
returns std::vector<std::unique_ptr<Child>>
而 Bar()
returns std::vector<std::unique_ptr<Parent>>
。没有办法规避这一点。但是,而不是:
std::vector<std::unique_ptr<Parent>> Bar() {
auto children = Foo();
std::vector<std::unique_ptr<Parent>> parents;
result.insert(result.end(), std::make_move_iterator(children.begin()),
std::make_move_iterator(children.end()));
return parents;
}
你可以这样做:
std::vector<std::unique_ptr<Parent>> Bar() {
auto tmp = Foo();
return {std::make_move_iterator(tmp.begin()), std::make_move_iterator(tmp.end()));}
}
好吧,我们可以在其他地方编写样板文件:
templace<class Cin>
struct move_from_c{
Cin* c;
template<class Cout>
operator Cout()&&{
using std::begin; using std::end;
return {std::make_move_iterator(begin(*c)), std::make_move_iterator(end(*c))};
}
};
template<class C, class dC=std::remove_reference_t<C>>
move_from_c<dC> move_from(C&&c){
return {std::addressof(c)};
}
然后你的函数是:
std::vector<std::unique_ptr<Parent>> Bar() {
return move_from(Foo());
}
这将实现细节从 Bar
的业务逻辑中分离出来。 (移动的完成方式与移动的决定分开)。
建议您使用 handle/body 惯用法并将多态性实现为句柄的实现细节 class。
这为您提供了值语义(在容器中工作),还允许您轻松实现关系运算符:
#include <vector>
#include <memory>
class ParentImpl {
public:
virtual ~ParentImpl() = default;
virtual void foo() {}
};
class ChildImpl : public ParentImpl {};
class ParentHandle
{
public:
using ptr_type = std::unique_ptr<ParentImpl>;
// construct from ptr_type
ParentHandle(ptr_type ptr = nullptr) : ptr_(std::move(ptr_)) {}
// public interface defers to polymorphic implementation
void foo()
{
ptr_->foo();
}
private:
std::unique_ptr<ParentImpl> ptr_;
};
static std::vector<ParentHandle> Foo()
{
std::vector<ParentHandle> result;
result.emplace_back(std::make_unique<ParentImpl>());
result.emplace_back(std::make_unique<ChildImpl>());
return result;
}
几种"simpler"方式:
#include <algorithm>
#include <iterator>
std::vector<std::unique_ptr<Base>> f1(std::vector<std::unique_ptr<Derived>> v)
{
std::vector<std::unique_ptr<Base>> result;
result.reserve(v.size());
std::move(v.begin(), v.end(), std::back_inserter(result));
return result;
}
std::vector<std::unique_ptr<Base>> f2(std::vector<std::unique_ptr<Derived>> v)
{
return {std::make_move_iterator(v.begin()), std::make_move_iterator(v.end())};
}
假设这段代码:
class Parent {}
class Child : public Parent {}
static std::vector<std::unique_ptr<Child>> Foo();
这个函数有没有更简单的写法:
std::vector<std::unique_ptr<Parent>> Bar() {
auto children = Foo();
std::vector<std::unique_ptr<Parent>> parents;
result.insert(result.end(), std::make_move_iterator(children.begin()),
std::make_move_iterator(children.end()));
return parents;
}
这行不通:
std::vector<std::unique_ptr<Parent>> Bar() {
return Foo(); // Compiler error: cannot convert from vector<...> to vector<...>
}
类型不同。 Foo()
returns std::vector<std::unique_ptr<Child>>
而 Bar()
returns std::vector<std::unique_ptr<Parent>>
。没有办法规避这一点。但是,而不是:
std::vector<std::unique_ptr<Parent>> Bar() {
auto children = Foo();
std::vector<std::unique_ptr<Parent>> parents;
result.insert(result.end(), std::make_move_iterator(children.begin()),
std::make_move_iterator(children.end()));
return parents;
}
你可以这样做:
std::vector<std::unique_ptr<Parent>> Bar() {
auto tmp = Foo();
return {std::make_move_iterator(tmp.begin()), std::make_move_iterator(tmp.end()));}
}
好吧,我们可以在其他地方编写样板文件:
templace<class Cin>
struct move_from_c{
Cin* c;
template<class Cout>
operator Cout()&&{
using std::begin; using std::end;
return {std::make_move_iterator(begin(*c)), std::make_move_iterator(end(*c))};
}
};
template<class C, class dC=std::remove_reference_t<C>>
move_from_c<dC> move_from(C&&c){
return {std::addressof(c)};
}
然后你的函数是:
std::vector<std::unique_ptr<Parent>> Bar() {
return move_from(Foo());
}
这将实现细节从 Bar
的业务逻辑中分离出来。 (移动的完成方式与移动的决定分开)。
建议您使用 handle/body 惯用法并将多态性实现为句柄的实现细节 class。
这为您提供了值语义(在容器中工作),还允许您轻松实现关系运算符:
#include <vector>
#include <memory>
class ParentImpl {
public:
virtual ~ParentImpl() = default;
virtual void foo() {}
};
class ChildImpl : public ParentImpl {};
class ParentHandle
{
public:
using ptr_type = std::unique_ptr<ParentImpl>;
// construct from ptr_type
ParentHandle(ptr_type ptr = nullptr) : ptr_(std::move(ptr_)) {}
// public interface defers to polymorphic implementation
void foo()
{
ptr_->foo();
}
private:
std::unique_ptr<ParentImpl> ptr_;
};
static std::vector<ParentHandle> Foo()
{
std::vector<ParentHandle> result;
result.emplace_back(std::make_unique<ParentImpl>());
result.emplace_back(std::make_unique<ChildImpl>());
return result;
}
几种"simpler"方式:
#include <algorithm>
#include <iterator>
std::vector<std::unique_ptr<Base>> f1(std::vector<std::unique_ptr<Derived>> v)
{
std::vector<std::unique_ptr<Base>> result;
result.reserve(v.size());
std::move(v.begin(), v.end(), std::back_inserter(result));
return result;
}
std::vector<std::unique_ptr<Base>> f2(std::vector<std::unique_ptr<Derived>> v)
{
return {std::make_move_iterator(v.begin()), std::make_move_iterator(v.end())};
}