Reputation: 1339
Consider the following piece of code:
CodeBuilder code = CodeBuilder{"Dog"}.add_field("name", "std::string").add_field("legs", "int");
and the following implementation:
class CodeBuilder
{
MyString _code;
public:
CodeBuilder(const std::string& class_name) //Initialize _code
{
}
CodeBuilder& add_field(const std::string& name, const std::string& type)
{
//Some implementation
return *this;
}
};
and MyString class:
class MyString
{
std::string str;
public:
MyString()
{
std::cout << "Default Ctor" << std::endl;
}
~MyString()
{
std::cout << "Destructor" << std::endl;
}
MyString(const MyString & other) : str(other.str)
{
std::cout << "Copy Ctor" << std::endl;
}
MyString & operator = (const MyString & other)
{
if(&other != this)
{
str = other.str;
}
std::cout << "Copy Assignment Operator" << std::endl;
return *this;
}
};
When I run the first block of code, the copy constructor (of CodeBuilder) is also invoked and this is the output:
Default Ctor
Copy Ctor
Destructor
Destructor
I then tried to change the above code to (i.e. adding reference):
CodeBuilder & code = CodeBuilder{"Dog"}.add_field("name", "std::string").add_field("legs", "int");
and only the default constructor was called, but this is really bad idead since this way i'm keeping reference to an already destructed object (and when i tried to print the results, gibberish was printed).
I wanted to know if there is a way to both invoke only one constructor (i.e. somehow construct the object directly to my variable) and still get the correct results ?
The only optimization i could think of is moving the temporary object instead of copying it.
Upvotes: 1
Views: 320
Reputation: 75785
If you preserve the reference type on add_field
:
class CodeBuilder
{
MyString _code;
void add_field_impl(const std::string& name, const std::string& type);
public:
/* ... */
CodeBuilder& add_field(const std::string& name, const std::string& type) &
// ^ ^
// lvalue lvalue
{
add_field_impl(name, type);
return *this;
}
CodeBuilder&& add_field(const std::string& name, const std::string& type) &&
// ^ ^
// rvalue rvalue
{
add_field_impl(name, type);
return std::move(*this);
}
};
the move constructor will be invoked instead without any modifications on the calling site:
CodeBuilder code = CodeBuilder{"Dog"}.add_field("name", "std::string")
.add_field("legs", "int");
// ^
// move constructor
Upvotes: 1