我想在现代C ++中实现构建器模式。来自Java背景,这是我想要模仿的东西:
// Usage
FooBuilder builder;
builder.setArg1(a);
builder.setArg2(b);
Foo foo = builder.build();
// Implementation
public class FooBuilder {
// ...
public Foo build() {
return new Foo(a, b);
}
}
典型的旧教科书只是建议一个人在C ++中这样做:
class FooBuilder {
// ...
Foo* build() {
return new Foo(m_a, m_b);
}
}
这显然不是一个好主意,因为处理原始指针可能容易出错。到目前为止,我提出的最好的方法是手动使用std::unique_ptr
:
class FooBuilder {
// ...
std::unique_ptr<Foo> build() {
return std::make_unique<Foo>(m_a, m_b);
}
}
// Usage
auto fooPtr = builder.build();
Foo& foo = *fooPtr;
foo.someMethod();
它更好,因为它不需要手动delete
,这个双线程转换为引用是丑陋的,更重要的是,它使用堆分配,而简单的无构建器版本将完全没问题只需一个简单的堆栈分配:
Foo foo(..., ...); // <= on stack
有没有更好的方法可以做到这一点,即没有unique_ptr,或者为Foo进行某种堆栈分配?
答案 0 :(得分:5)
没有理由让 在堆上分配以使用构建器模式。只需让您的build()
方法直接返回Foo
:
class FooBuilder {
public:
Foo build() { // You may consider having a &&-qualified overload
return Foo{ ..., ... };
}
};
答案 1 :(得分:4)
通常,如果Foo是copy_constructible,那么您可以按值返回Foo。
#include <type_traits>
class Foo
{
int i;
public:
Foo(int i): i(i){}
};
static_assert(std::is_copy_constructible<Foo>::value, "Foo is copy-constructible");
struct FooFactory
{
//...
Foo build() {return Foo(1);}
};
int main()
{
FooFactory factory;
//...
Foo foo = factory.build();
}
c ++ 17中的新内容是guaranteed copy elision,这意味着即使类型没有复制或移动构造函数,也可以按值返回:
#include <type_traits>
class Foo
{
int i;
public:
Foo(int i): i(i){}
// regular copy constructors don't exist for whatever reason.
Foo() = delete;
Foo(Foo const& ) =delete;
Foo(Foo&& ) = delete;
Foo& operator=(Foo const&) = delete;
Foo& operator=(Foo&& ) = delete;
};
static_assert(not std::is_copy_constructible<Foo>::value, "Foo is definitely not copy-constructible");
struct FooFactory
{
//...
Foo build() {return Foo(1);}
};
int main()
{
FooFactory factory;
//...
Foo foo = factory.build();
}