Does it make sense to overload set(/*args*/) with move?:
//example:
class Person {
private:
//properties
std::string name;
std::string address;
std::string favmovie;
public:
//set without operator=
void set(const std::string& name, const std::string& address, const std::string& favmovie) {
this->name = name;
this->address = address;
this->favmovie = favmovie;
return;
}
//set without operator=
void set(std::string&& name, std::string&& address, std::string&& favmovie) {
this->name = std::move(name);
this->address = std::move(address);
this->favmovie = std::move(favmovie);
return;
}
Person(const std::string& name, const std::string& address, const std::string& favmovie)
: name(name), address(address), favmovie(favmovie) {
}
Person(std::string&& name, std::string&& address, std::string&& favmovie)
: name(std::move(name)), address(std::move(address)), favmovie(std::move(favmovie)) {
}
};
It feels like copy and paste with a little bit of editing but I'm doing this to every function or method with congruent purposes I have so far to make them high-performing. But is this a good practice?
#M.M's answer has the disadvantage that storage will be reallocated every time set is called, while passing the arguments by reference will allow the data to simply be copy-assigned without reallocation whenever their capacity is already sufficient to hold the data passed in via the arguments. See Herb Sutter's CppCon talk for more details. So I would recommend
void set(const std::string &name, const std::string &adress, const std::string &favmovie)
{
this->name = name;
this->adress = adress;
this->favmovie = favmovie;
}
The constructors could use the clever pass-by-value trick, but unless it is really low level code that gets beat on a lot the optimization there is likely not worth it, IMO.
This is where you use pass-by-value:
void set(std::string name, std::string adress, std::string favmovie)
{
this->name = std::move(name);
this->adress = std::move(adress);
this->favmovie = std::move(favmovie);
}
Then if the argument is an rvalue it will be moved into the parameter than then moved into this - two moves, no copies. Whereas with the const lvalue reference version, there is always a copy. For the case of an lvalue argument there is 1 copy in both cases (and 1 extra move in the value version, but moves are cheap and may be elided anyway).
If the function's purpose itself does not benefit from move semantics, and the function would not benefit from having a reference to a mutable parameter, there is no reason to have an overloaded version that takes an rvalue reference as a parameter.
For the simple function shown here, the answer is obviously no. But it wouldn't be too hard to think of an example where the function would store its parameter someplace. In that case, having an overloaded version that takes advantage of move semantics, instead of having to copy-construct the object for the purpose of storing it, would have obvious benefits.
It all comes down to what the function needs its parameter for.
Related
Considering the following class example :
class AClass
{
std::string myString;
public:
...
}
With one of the following accessors :
const std::string& GetMyString() const
{
return myString;
}
versus
const char* GetMyString() const
{
return myString.c_str();
}
Taking into account that myString is initialized once and is never changed, which accessor is better? The first one, or the second one? In what situation one of them is more suitable than its neighbor?
The version returning const std::string& covers a superset of the use cases for returning const char* (after all, it can be converted to the latter by calling .c_str() on the return value), with no added weaknesses. Given that std::string is more flexible in other ways, I'd prefer const std::string& of the two options.
That said, they're both awkward if the owning object in question isn't immortal; even if the string is never changed, if the object itself disappears, the reference to its string is now invalid. If that's a possibility, you might want to either:
Return by value
or
Use a std::shared_ptr<std::string> member and return that (so the lifetime of the string is no longer tied to the lifetime of the object that created it)
I just started working with c++11 r-values. I read some tutorials, but I haven't found the answer.
What is the best way (the most efficient way) to set a class variable? Is below code correct or not? (let's assume std::string has defined move constructor and assignment operator).
class StringWrapper
{
private:
std::string str_;
public:
StringWrapper() : str_("") {}
void setString1(std::string&& str) {
str_ = std::move(str);
}
void setString2(const std::string& str) {
str_ = std::move(str);
}
// other possibility?
};
int main() {
std::string myText("text");
StringWrapper x1, x2;
x1.setString?("text"); // I guess here should be setString1
x2.setString?(myText); // I guess here should be setString2
}
I know that compiler can optimize my code and/or I can use overload functions. I'd like to only know what is the best way.
Herb Sutter's advice on this is to start with the standard C++98 approach:
void setString(const std::string& str) {
str_ = str;
}
And if you need to optimize for rvalues add an overload that takes an rvalue reference:
void setString(std::string&& str) noexcept {
str_ = std::move(str);
}
Note that most implementations of std::string use the small string optimization so that if your strings are small a move is the same as a copy anyway and you wouldn't get any benefit.
It is tempting to use pass-by-value and then move (as in Adam Hunyadi's answer) to avoid having to write multiple overloads. But Herb pointed out that it does not re-use any existing capacity of str_. If you call it multiple times with lvalues it will allocate a new string each time. If you have a const std::string& overload then it can re-use existing capacity and avoid allocations.
If you are really clever you can use a templated setter that uses perfect forwarding but to get it completely correct is actually quite complicated.
Compiler designers are clever folk. Use the crystal clear and therefore maintainable
void setString(const std::string& str) {
str_ = str;
}
and let the compiler worry about optimisations. Pretty please, with sugar on top.
Better still, don't masquerade code as being encapsulated. If you intend to provide such a method, then why not simply make str_ public? (Unless you intend to make other adjustments to your object if the member changes.)
Finally, why don't you like the default constructor of std::string? Ditch str_("").
The version with rvalue reference would not normally bind to an lvalue (in your case, mytext), you would have to move it, and therefore construct the object twice, leaving you with a dangerous object. A const lvalue reference should be slower when constructing from an rvalue, because it would do the same thing again: construct -> move -> move construct.
The compiler could possibly optimize the overhead away though.
Your best bet would actually be:
void setString(std::string str)
{
str_ = std::move(str);
}
The compiler here is suprisingly guaranteed to deduce the type of the argument and call the copy constructor for lvalues and the move constructor for rvalues.
Update:
Chris Dew pointed out that constructing and move assigning a string is actually more expensive than copy constructing. I am now convinced that using a const& argument is the better option. :D
You might probably use templatized setString and forwarding references:
class StringWrapper
{
private:
std::string str_;
public:
template<typename T>
void setString(T&& str) {
str_ = std::forward<T>(str);
}
};
I have a class like that.I want to use reference for string but it doesnt work.How can i use string& ?
#include <string>
using namespace std;
class T
{
public:
T(string& s);
private:
string s;
};
T::T(string& s)
{
this->s = s;
}
int main(void)
{
T t("Test Object");
return 0;
}
Error : 'T::T(std::string &)' : cannot convert parameter 1 from 'const char [12]' to 'std::string &'
Use const :
class T
{
public:
T(const string& ss);
private:
string s;
};
T::T(const string& ss) : s(ss)
{
}
"Test Object" will be constructed as a const string before passing to T's constructor, so the constructor has to accept a const string.
You're not passing in a std::string. As it says, it can't convert from const char array to string-ref. Change the constructor to take a const-ref and it'll work. This is because a temporary string will have to be created from the char-array, and you can only make const-references to temporaries to stop you getting confused (if you modify the temporary, the changes are just going to be discarded, so the language stops you from doing that).
In C++98/03, if you have a class that is not cheap to copy (e.g. an int or a double are cheap to copy, a std::string isn't, since its copy can involve allocating new heap memory, copying characters from source to destination, etc.), then the rule is to pass by const reference const std::string&:
class T
{
public:
T(const string& s); // <--- const string&
private:
string m_s;
};
And then in constructor do:
T::T(const string& s)
: m_s(s)
{}
However, in C++11, where move semantics is available, the new rule seems to be: if you need a copy (and the object is cheap to move, as it normally should be), pass by value and move from the value:
T::T(string s) // pass by value
: m_s( std::move(s) ) // and move from the value
{}
(The optimal thing would be to offer a couple of overloads, passing by const & and passing by value, but probably this is not necessarily in all applications, but only when you need to squeeze performance.)
Note that when you don't need a copy, and just need to observe the parameter, the usual C++98/03 pass by const & rule is still valid.
The constructor you defined takes a std::string by reference:
T::T(std::string& s)
{
this->s = s;
}
thus the most straightforward thing to do would be to create a std::string object, that will be passed to this constructor:
std::string s("Test Object");
T t(s);
But since your constructor doesn't change the std::string you pass to it (it is just used to set the value of T's data member) you should pass const reference: T::T(const string& s). Also instead of letting the data member s being constructed and assigning another string into it later, it would be better if you construct this member directly within an initialization list:
T::T(const std::string& str) : s(str) { }
References need to be intialized using the initialiser-list of the constructor. Change your constructor to:
T::T(string& s) : s(s)
{
}
Additionally define your member s as std::string& s to be able to take a reference.
Maybe change the name of s to avoid ambiguities.
See this entry on SO.
I was trying to evaluate how rvalue references effect the design of the class. Say I have an existing class as shown below
class X
{
string internal;
public:
void set_data(const char* s)
{
internal = s;
}
..
..
..
//other stuff
};
This class is used by another module like this:
//another module
{
string configvalue;
X x;
//read configvalue from a file and call set
...
x.set_data(configvalue.c_str());
//use x to do some magic
..
...
}
with rvalue references in place will it be better to provide another member function like so
class X
{
...
...
....
void set_data(string s)
{
internal = std::move(s);
}
};
This will allow the clients of this class to use move semantics and prevent one set of allocate/copy operations per use. This is a highly concocted example but does the same principle apply to all class designs without breaking the 'minimal interface' paradigm.
Anybody insights on this matter are greatly appreciated?
Yes, adding the string overload as you suggest is a good idea. Even without rvalue references such an overload would be a good idea. Otherwise, given a std::string s, to use it would have to:
x.set_data(s.c_str());
whereas
x.set_data(s);
is so much more intuitive (and even slightly more efficient) for the clients of X.
As another option, you could add these two overloads:
void set_data(const string& s) {internal = s;}
void set_data(string&& s) {internal = std::move(s);}
This is roughly equivalent to the single overload you correctly suggested. There is a very slight performance advantage for the two-overload solution. The single-overload solution will cost an extra string move construction when the argument passed is an xvalue (an lvalue that has been cast with std::move). But the move constructor of std::string should be really fast, so this should not be a big deal. I mention it only in the spirit of full disclosure.
If set_data has more than one parameter, the "by-value" approach becomes much more attractive. For example consider the case where you need to pass in two strings. Your choices are:
Solution 1
void set_data(string s1, string s2);
Solution 2
void set_data(const string& s1, const string& s2);
void set_data( string&& s1, const string& s2);
void set_data(const string& s1, string&& s2);
void set_data( string&& s1, string&& s2);
As you can quickly see, Solution 2 scales poorly with the number of parameters.
Finally, in no circumstance should you attempt to apply both solutions to the same type:
Don't do this!
void set_data(string s) {internal = std::move(s);}
void set_data(const string& s) {internal = s;}
void set_data(string&& s) {internal = std::move(s);}
This set of overloads will be ambiguous. Just as in C++03 the following two overloads are ambiguous:
void set_data(string s) {internal = std::move(s);}
void set_data(const string& s) {internal = s;}
Never overload by-value with reference, either lvalue reference nor rvalue reference.
I don't see a reason to have both void set_data(const char* s) and void set_data(string s) as part of the interface. This will create an ambiguity and is prone to side-effects. Moreover, you still pass the argument by value in call to set_data(string s). Instead I would suggest defining the 2 following funcs:
void set_data(const string &s);
void set_data(string &&s);
This way you can have 2 implementations, first will deep copy your string and second one can steal the internals of the string since it's an rvalue (make sure to leave it in a defined state so the destructor will be able to destroy it without problem - for details see http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2006/n2027.html#Move_Semantics).
The second version will be invoked automatically either on rvalue string argument or if argument is forced to rvalue, for example by std::move.
If you want to have a by-value option as well you can use the rvalue version of this API combined with string copy constructor: set_data(string(str)).
Let say I am designing an interface, to return the name of the child class. Note that, for different instance of a child class, their name shall remain the same.
For speed and memory efficient, I would say 3rd method signature is probably the best (based on some comment from char* vs std::string in c++)
virtual const std::string& name2() const = 0;
I was wondering is there any better alternative?
#include <cstdio>
#include <string>
class baby_interface {
public:
virtual const char* name0() const = 0;
virtual std::string name1() const = 0;
virtual const std::string& name2() const = 0;
};
class baby : public baby_interface {
public:
virtual const char* name0() const
{
return "My Baby";
}
virtual std::string name1() const
{
return "My Baby";
}
virtual const std::string& name2() const
{
return std::string("My Baby");
}
};
int main()
{
baby b;
// Refer to same char array address.
printf("%x\n", b.name0());
printf("%x\n\n", b.name0());
// Refer to different char array address.
printf("%x\n", b.name1().c_str());
printf("%x\n\n", b.name1().c_str());
// Refer to same char array address.
printf("%x\n", b.name2().c_str());
printf("%x\n\n", b.name2().c_str());
getchar();
}
It can be if you do it correctly. What you have now is undefined:
virtual const std::string& name2() const
{
return std::string("My Baby"); // constructs temporary string!
}
You're returning a reference to a temporary. For this to work, it must be an l-value. You could make it static:
virtual const std::string& name2() const
{
static const std::string result = "My Baby";
return result;
}
Or a member of the class, etc. Now it returns a usable variable.
I don't have much experience in what's common, but I'd guess number one is common if these interfaces are being used between modules. (i.e., the interface as allocated from a shared library/dll). This is because the implementation of strings is likely differ between compilers, and sometimes even different versions of the same compiler. If the program was made with one implementation, while the derived's was made in another, transferring between the two could fail.
By using a const char * (which is the same in all compilers), you avoid that. However, const char * can look unsightly to some.
The second options seems to be what I would use, because forcing derived classes to make a static/l-value variable might not be what you should do. The copy is likely to be very quick anyway.
Returning by value (your name1) is actually the most flexible, as it poses the least restrictions on any subclasses.
Returning a const reference (your name2) requires the subclass to store the data, as your code above shows, since you have Undefined Behavior returning a reference to a local (temporary) object.
Returning a pointer (your name0) is common when the strings are known at compile-time, as regular string literals can be used easily and with no overhead.
The third message signature doesn't work: You are returning a reference to an object that is destroyed when the method exits. Returning a reference makes sense when the object has a lifetime longer than the method call (eg. it is a member variable, a static, etc.).
The first two are OK; an third alternative is:
void name3(std::string* target) const
{
*target = whatever;
}
Basic tradeoffs:
const char* is good for communicating with C code, and when the strings are real constants with a long lifetime, also when crossing module boundaries where the runtime environment might not be consistent.
std::string is good when the contents of the string are generated in the method and the caller needs to take responsibility for the lifetime of the object. Whether you return a value or pass a pointer/reference for the method to modify is a detail.
const std::string& is good when there is a well-defined lifetime for the reference and it makes sense in the context of the actual method. This is good when strings are generated in a class and repeatedly used.
The return type depends on your usage. If you are returning a constant you should use either option 0 or 1 (const char* or std::string) with const char* being a little more flexible (the user can capture it as a C-string or else as a c++ string), and std::string being more c++-like. I would rather go for the second.
On the other hand, if you are returning a value that you already have stored (a member attribute) then I would go for 2. There is no need to create a copy, and a C-style string would require managing memory ownership and documenting (is the caller responsible for deletion, or is the memory managed elsewhere? how long is the pointed value valid (.c_str() will become invalid after some mutating operations on the string).
So to sum up:
class X {
std::string name_;
public:
const char* constant1() const { return "constant"; }
std::string constant2() const { return "constant"; } // preferred over constant1
std::string const & name() const { return name_; } // internal data
std::string const & constant3() const {
// valid, more complex than needed, requires creating static data
static std::string the_constant = "constant";
return the_constant;
}
};