HiveBrain v1.2.0
Get Started
← Back to all entries
patterncppMinor

Builder/named argument/fluent interface pattern with unique_ptr

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
argumentbuilderwithnamedinterfacefluentunique_ptrpattern

Problem

I'm trying to figure out the cleanest way to implement a fluent interface with unique_ptr and other "modern" C++ language constructs. Here's my first attempt:

```
#include
#include
#include

// Backported from C++14
namespace std
{
template
std::unique_ptr make_unique(Args &&... args)
{
return std::unique_ptr(new T(std::forward(args)...));
}
}

using namespace std;

class Widget
{
Widget() = delete;
Widget(Widget const &) = delete;
Widget(Widget &&) = delete;
Widget &operator=(Widget const &) = delete;
Widget &operator=(Widget &&) = delete;

public:
Widget(string const &name) :
m_name(name)
{ }

~Widget()
{ }

string const &name() const
{ return m_name; }

private:
string const m_name;
};

class WidgetBuilder
{
WidgetBuilder(WidgetBuilder const &) = delete;
WidgetBuilder(WidgetBuilder &&) = delete;
WidgetBuilder &operator=(WidgetBuilder const &) = delete;
WidgetBuilder &operator=(WidgetBuilder &&) = delete;

public:
WidgetBuilder()
{ }

~WidgetBuilder()
{ }

WidgetBuilder &name(string const &name)
{ m_name = name; return *this; }

unique_ptr create()
{ return make_unique(m_name); }

private:
string m_name;
};

class WidgetContainer
{
WidgetContainer() = delete;
WidgetContainer(WidgetContainer const &) = delete;
WidgetContainer(WidgetContainer &&) = delete;
WidgetContainer &operator=(WidgetContainer const &) = delete;
WidgetContainer &operator=(WidgetContainer &&) = delete;

public:
WidgetContainer(
string const &firstName,
string const &lastName,
unique_ptr>> widgets) :
m_firstName(firstName),
m_lastName(lastName),
m_widgets(move(widgets))
{ }

~WidgetContainer()
{ }

string const &firstName() const
{ return m_firstName; }

string const &lastName() const
{ return m_lastName; }

vector> const &widgets() const
{ return *m_widg

Solution

Please don't do this:

using namespace std;


See: Why is “using namespace std;” considered bad practice?

I would change a couple of things:

In WidgetBuilder

I don't like the explicit call to create() WidgetBuilder.

unique_ptr create()
{ return make_unique(m_name); }


I would replace it with a conversion operator:

operator std::unique_ptr()
{    return std::make_unique(m_name);}


Then usage becomes:

unique_ptr  val = WidgetBuilder().name("Loki");


In WidgetContainer

I don't see the need to put the std::vector inside a std::uniqu_ptr.

unique_ptr>> m_widgets;


I would just do

std::vector>> m_widgets;


Because of RVO and NRVO this is very efficient when returning objects. Also with the use of "Move Semantic" even passing it as a parameter is now very efficient.

In WidgetContainerBuilder

Like WidgetBuilder remove the create() method.

Not sure I would pass WidgetBuilder to the addWidget() method. Why not a std::unique_ptr create them on the fly and use them as needed. (I suppose this is why you had an explicit create() method on Widget.

WidgetContainerBuilder &addWidget(WidgetBuilder &widgetBuilder)

Code Snippets

using namespace std;
unique_ptr<Widget> create()
{ return make_unique<Widget>(m_name); }
operator std::unique_ptr<Widget>()
{    return std::make_unique<Widget>(m_name);}
unique_ptr<Widget>  val = WidgetBuilder().name("Loki");
unique_ptr<vector<unique_ptr<Widget>>> m_widgets;

Context

StackExchange Code Review Q#56360, answer score: 3

Revisions (0)

No revisions yet.