Return std::string as const reference - c++

I have a doubt on returning std::string as const reference.
class sample
{
public:
std::string mString;
void Set(const std::string& s)
{
mString = s;
}
std::string Get()
{
return mString;
}
};
In the Set function I am passing the std::string as const reference, const because its value is not changing inside the function.
And In Get function, actually I am confused here. Return std::string as value makes more sense. But I am not sure that, by passing the string as const reference makes any advantages. By returing string as reference will increase the exectuion speed, I think So, but I am not sure. But returning it as 'const makes any benefit for this?

The problem of deciding how to return a non-trivial object from some sort of a container is actually non-trivial:
If the class from which you return your value imposes any sort of constraint on the object, you can't return a non-const reference because it would loose the possibility to enforce its invariants. Clearly, returning an object by non-const reference is only viable if object the member function is called on is also non-const.
Exposing a const reference to an object would avoid the problem with the invariants but still implies that an object of the corresponding type is actually kept internally as an implementation detail.
Returning an object by value may incur a significant cost for copying the object.
If you class is further a viable monitor you definitely want to return the object by value because otherwise the object can be mutated before the caller had any chance to copy it.
Basically, none of the choices is ideal. When in doubt, I return by value unless the object is known to be expensive to copy in which case I might return by const&.

Returning by reference or const reference has no speed difference - both are very fast as they just return a reference to the original object, no copying is involved.
An object returned by (non-const) reference can be modified through that reference. In your specific example, mString is public, so it can be modified anyway (and directly). However, the usual approach with getters and setters (and the primary reason for their introduction) is encapsulation - you only allow access to your data members through the getter/setter, so that you can detect invalid values being set, respond to value changes and just generally keep the implementation details of your class hidden inside it. So getters normally return by const reference or by value.
However, if you return by const reference, it binds you to always keep an instance of std::string in your class to back up the reference. That is, even if you later want to redesign your class so that it computes the string on the fly in the getter instead of storing it internally, you can't. You'd have to change your public interface at the same time, which can break code using the class. For example, as long as you return by const-reference, this is perfectly valid code:
const std::string *result = &aSample.Get();
This code will of course produce a dangling pointer no longer compile if Get() is changed to return by value instead of const reference. (thanks to Steve Jessop for correcting me)
To sum up, the approach I would take is to make mString private. Get() can return by value or by const-reference, depending on how certain you are that you'll always have a string stored. The class would then look like this:
class sample
{
std::string mString;
public:
void Set(const std::string &s)
{
mString = s;
}
std::string Get() const
{
return mString;
}
};

The most common thing to do here would be to return the value as a const-reference, then you can use a reference or copy the value as necessary:
const std::string& Get() const
{
return mString;
}
sample mySample;
const std::string &refString = mySample.Get(); // Const-reference to your mString
const std::string copyString = mySample.Get(); // Copy of your mString
If you really need to return a copy of the string, then you can avoid copying the string return value by utilising "The Most Important Const":
sample mySample;
const std::string &myString = mySample.Get();
// myString is now valid until it falls out of scope, even though it points to a "temporary" variable

Return it as a reference. If a copy is needed, it certainly can be made from that reference.

Related

In C++, if a funcion takes in a const std::string& as input, can I always call with std::move() on the string input?

I don't know much about the function, except it takes a const std::string&, and I want to call this function from inside a class, and the string input I'm sending in is returned from an instance function on this class.
Is std::move() usage here always safe and more performant, given what we know?
//In some header file:
void some_func_I_only_know_its_signature(const std::string& string_input);
public MyClass{
public:
void myFunc(){
some_func_I_only_know_its_signature(std::move(getMyString()));
}
private:
std::string getMyString(){
return myString;
}
std::string myString_;
};
std::move actually does absolutely nothing here:
some_func_I_only_know_its_signature(std::move(getMyString()));
The return value of getMyString is already an rvlaue. The thing is std::move actually doesn't move anything. This is a common misconception. All it does is cast an lvalue to an rvalue. If the value is an rvalue and has a move constructor (sdt::string does) it will get moved. But in this case, since the function does not expect an rvalue reference either way you are just going to pass a reference to the return value of getMyString() So you can just:
some_func_I_only_know_its_signature(getMyString());
That being said the most performant ways is to just:
some_func_I_only_know_its_signature(myString_);
The function expects a const& which means it only wants read access. Your getMyString() function creates a copy of myString_ and returns it. You don't have to create a copy here, you can just pass a reference to your string directly. get/set functions are usually used for controlled public access to a private field from outside the class.

Is there any point in returning an object (e.g., std::string) by reference when the method has no parameters?

Take the following snippet of code
#include <iostream>
#include <string>
class Foo {
private:
std::string m_name;
public:
Foo(std::string name) : m_name { name } {}
const std::string & get_name() const { return m_name; }
};
int main() {
Foo x { "bob" };
x.get_name();
}
Because I initialized an object and name exists somewhere in memory, is a temporary object is made when I call the x.get_name()? If a temporary object is made, than is there a point to returning by reference? My understanding is you return by reference so to avoid the cost of creating a large object or when using an std::ostream& object because you have to.
Yes, there is a point, you return by reference if you want to return a reference to some object.
Why would you want to have a reference to some object? Exactly because you need to access it and not a copy of it. Reasons might vary, basic ones are that you do not want to make an extra copy - e.g. the get_name you posted, maybe you want to store it and access it later, and/or because you want to modify it.
Returning a reference is not much different from a passing parameter by reference.
No temporary std::string object is made in x.get_name(). The method returns lvalue reference by value. Since references are usually implemented as pointers, the true return value is a pointer. So a copy of the pointer is made during each call but that is like returning an int - can be done in registers or stack. So it's as cheap as it gets.
Yes, your understanding is correct, although I would say that const T& is used when we want to avoid copy for whatever reasons and T& should only be used when we need to get mutable access to the object - e.g. std::ostream& in operator<< which mutates the stream by printing into it.
BTW, you make an extra copy in your ctor - name parameter is copied into name member. Instead you should move it there like Foo(std::string name):name(std::move(name)){}.

Return a "const char*" as std::string& from a class method

I have a C-Libraray function returning a C-String
const char* myFuncC(struct myS *);
Now I write a class mapper:
class myC {
private:
struct myS * hdl
...
public:
const char* myFunc() {
return myFuncC(hdl);
}
// want to have...
const std::string& myFuncS() {
return ??? myFuncC(hdl);
}
}
Now I would like to return a: const std::string& and I don't want to copy the C-String pointer data
How I do this?
update
Is there a C++ Class who act like a const C++-String class and using a const C-String pointer as string source ?
I would call this class a C++-String-External … External mean … using a external source as storage… in my case a "const char *"
std::string, by definition, owns its memory and there’s nothing we can do to change this. Furthermore, by returning a reference you’re creating a dangling reference to a local variable (or a memory leak).
However, the idea of encapsulating contiguous character ranges in a string-like interface without copying is such a common problem that C++17 added a new type, std::string_view, to accomplish exactly that. With it, your code can be written as:
std::string_view myFuncS() {
return {myFuncC(hdl)};
}
A string_view isn’t a string but it has a very similar API and the idea is to use it instead of many current uses of string const&. It’s perfect for the job here.
Note that we are returning a copy, to avoid a dangling reference. However, this does not copy the underlying memory, and is cheap — almost as cheap as returning the reference.
Simply return a new string:
std::string myFuncS() {
return std::string(myFuncC(hdl));
}
If you really need a refence or a pointer then allocate the string on the heap and return a pointer to it:
std::unique_ptr<std::string> myFuncS() {
return std::unique_ptr<std::string>(new std::string(myFuncC(hdl)));
}

How to write a getter method so that it returns an rvalue

If we have this class definition
class BusDetails
{
private:
string m_busName;
public:
string BusName() const { return m_busName; }
};
how could the getter method be changed or used, so that using the return value as an lvalue would give a compiler error?
For example, if I use it like
int main(void)
{
BusDetails bus;
bus.BusName() = "abc"; // <--- This should give a compiler error
cout << bus.BusName() << endl;
return 0;
}
I get no compiler error, so apparently the assignment works, but the result is not as expected.
Update: this behavior is as expected with build-in types (i.e. the compiler gives an error at the above line of code if I have an int as a return type instead of string).
The BusName() was declared as a const function. So it can't change members.
Your function should return string& and not be const.
string& BusName() { return m_busName; }
In addition you can add for const object (this is const):
const string& BusName() const { return m_busName; }
It's not clear what behavior you want.
If you want the assignment to be an error, and keep all of the
flexibility of value return (e.g. you can modify the code to
return a calculated value), you can return std::string const.
(This will inhibit move semantics, but that's generally not
a big issue.)
If you want to be able to modify the "member", but still want
to retain flexibility with regards to how it is implemented in
the class, then you should provide a setter method. One
convention (not the only one) is to provide a getter function
like you have now (but returning std::string const), and
provide a function with the same name void
BusName( std::string const& newValue ) to set the value.
(Other conventions would use a name like SetBusName, or return
the old value, so client code could save and restore it, or
return *this, so client code could chain the operations:
obj.BusName( "toto" ).SomethingElse( /*...*/ ).
You may also provide a non-const member returning a reference
to a non-const. If you do this, however, you might as well make
the data member public.
Finally, you might provide a non-const member which returns
some sort of proxy class, so that assigning to it would in fact
call a setter function, and converting it to std::string would
call the getter. This is by far the most flexible, if you
want to support modifications by the client, but it's also by
far the most complex, so you might not want to use it unless you
need to.
Well it is kind of expected behavior what you have written.
You do return a copy of m_busName. Because you do not return the reference. Therefore a temporary copy of the return variable is made, and then the assignment takes place. operator= is "abc" called on that copy.
So the way to go would be string& BusName() const { return m_busName; }. But that shall give a compiler error.
You kind of want contradictory things. You say string BusName() const, yet you want to return a reference that will allow the state of the object to be changed.
However if you don't promise the object will not change you can drop the const and go with
string& BusName() { return m_busName; };
Or if you want to keep the const
const string& BusName() const { return m_busName; };
however this should give an error on the assignment, naturally.
The same goes for functions. If you do pass argument by reference it is a reference. If you see that you modify a copy, you must have not passed it by reference but by value.
The function does return an rvalue.
The problem is that std::string::operator= works with an rvalue on the left. Prior to C++11 it was difficult or impossible to prevent it from working: in C++11 they added (relatively late) what is colloquially known as rvalue references to this: the ability to overload methods and in-class operators based on the rvalue state of the object.
However, std::string was not modified, probably do to a mixture of not much time and dislike of breaking existing code without good reason.
You could patch around this problem a few ways. You could write your own string class that obeys rvalue reference to this. You could descend from std::string and block the operator= specifically. You could write an accessor object that has-a std::string that can cast-to std::string&& a d std::string& (based on rvalue status of this) implicitly, but blocks assignment with deleted method.
All three have issues. The last has the fewest issues, the second the most hidden pitfalls, the first is just drudgery.

Which are the implications of return a value as constant, reference and constant reference in C++?

I'm learning C++ and I'm still confused about this. What are the implications of return a value as constant, reference and constant reference in C++ ? For example:
const int exampleOne();
int& exampleTwo();
const int& exampleThree();
Here's the lowdown on all your cases:
• Return by reference: The function call can be used as the left hand side of an assignment. e.g. using operator overloading, if you have operator[] overloaded, you can say something like
a[i] = 7;
(when returning by reference you need to ensure that the object you return is available after the return: you should not return a reference to a local or a temporary)
• Return as constant value: Prevents the function from being used on the left side of an assignment expression. Consider the overloaded operator+. One could write something like:
a + b = c; // This isn't right
Having the return type of operator+ as "const SomeType" allows the return by value and at the same time prevents the expression from being used on the left side of an assignment.
Return as constant value also allows one to prevent typos like these:
if (someFunction() = 2)
when you meant
if (someFunction() == 2)
If someFunction() is declared as
const int someFunction()
then the if() typo above would be caught by the compiler.
• Return as constant reference: This function call cannot appear on the left hand side of an assignment, and you want to avoid making a copy (returning by value). E.g. let's say we have a class Student and we'd like to provide an accessor id() to get the ID of the student:
class Student
{
std::string id_;
public:
const std::string& id() const;
};
const std::string& Student::id()
{
return id_;
}
Consider the id() accessor. This should be declared const to guarantee that the id() member function will not modify the state of the object. Now, consider the return type. If the return type were string& then one could write something like:
Student s;
s.id() = "newId";
which isn't what we want.
We could have returned by value, but in this case returning by reference is more efficient. Making the return type a const string& additionally prevents the id from being modified.
The basic thing to understand is that returning by value will create a new copy of your object. Returning by reference will return a reference to an existing object. NOTE: Just like pointers, you CAN have dangling references. So, don't create an object in a function and return a reference to the object -- it will be destroyed when the function returns, and it will return a dangling reference.
Return by value:
When you have POD (Plain Old Data)
When you want to return a copy of an object
Return by reference:
When you have a performance reason to avoid a copy of the object you are returning, and you understand the lifetime of the object
When you must return a particular instance of an object, and you understand the lifetime of the object
Const / Constant references help you enforce the contracts of your code, and help your users' compilers find usage errors. They do not affect performance.
Returning a constant value isn't a very common idiom, since you're returning a new thing anyway that only the caller can have, so it's not common to have a case where they can't modify it. In your example, you don't know what they're going to do with it, so why should you stop them from modifying it?
Note that in C++ if you don't say that something is a reference or pointer, it's a value so you'll create a new copy of it rather than modifying the original object. This might not be totally obvious if you're coming from other languages that use references by default.
Returning a reference or const reference means that it's actually another object elsewhere, so any modifications to it will affect that other object. A common idiom there might be exposing a private member of a class.
const means that whatever it is can't be modified, so if you return a const reference you can't call any non-const methods on it or modify any data members.
Return by reference.
You can return a reference to some value, such as a class member. That way, you don't create copies. However, you shouldn't return references to values in a stack, as that results in undefined behaviour.
#include <iostream>
using namespace std;
class A{
private: int a;
public:
A(int num):a(num){}
//a to the power of 4.
int& operate(){
this->a*=this->a;
this->a*=this->a;
return this->a;
}
//return constant copy of a.
const int constA(){return this->a;}
//return copy of a.
int getA(){return this->a;}
};
int main(){
A obj(3);
cout <<"a "<<obj.getA()<<endl;
int& b=obj.operate(); //obj.operate() returns a reference!
cout<<"a^4 "<<obj.getA()<<endl;
b++;
cout<<"modified by b: "<<obj.getA()<<endl;
return 0;
}
b and obj.a "point" to the same value, so modifying b modifies the value of obj.a.
$./a.out
a 3
a^4 81
modified by b: 82
Return a const value.
On the other hand, returning a const value indicates that said value cannot be modified. It should be remarked that the returned value is a copy.:
For example,
constA()++;
would result in a compilation error, since the copy returned by constA() is constant. But this is just a copy, it doesn't imply that A::a is constant.
Return a const reference.
This is similiar to returning a const value, except that no copy is return, but a reference to the actual member. However, it cant be modified.
const int& refA(){return this->a;}
const int& b = obj.refA();
b++;
will result in a compilation error.
const int exampleOne();
Returns a const copy of some int. That is, you create a new int which may not be modified. This isn't really useful in most cases because you're creating a copy anyway, so you typically don't care if it gets modified. So why not just return a regular int?
It may make a difference for more complex types, where modifying them may have undesirable sideeffects though. (Conceptually, let's say a function returns an object representing a file handle. If that handle is const, the file is read-only, otherwise it can be modified. Then in some cases it makes sense for a function to return a const value. But in general, returning a const value is uncommon.
int& exampleTwo();
This one returns a reference to an int. This does not affect the lifetime of that value though, so this can lead to undefined behavior in a case such as this:
int& exampleTwo() {
int x = 42;
return x;
}
we're returning a reference to a value that no longer exists. The compiler may warn you about this, but it'll probably compile anyway. But it's meaningless and will cause funky crashes sooner or later. This is used often in other cases though. If the function had been a class member, it could return a reference to a member variable, whose lifetime would last until the object goes out of scope, which means function return value is still valid when the function returns.
const int& exampleThree();
Is mostly the same as above, returning a reference to some value without taking ownership of it or affecting its lifetime. The main difference is that now you're returning a reference to a const (immutable) object. Unlike the first case, this is more often useful, since we're no longer dealing with a copy that no one else knows about, and so modifications may be visible to other parts of the code. (you may have an object that's non-const where it's defined, and a function that allows other parts of the code to get access to it as const, by returning a const reference to it.
Your first case:
const int exampleOne();
With simple types like int, this is almost never what you want, because the const is pointless. Return by value implies a copy, and you can assign to a non-const object freely:
int a = exampleOne(); // perfectly valid.
When I see this, it's usually because whoever wrote the code was trying to be const-correct, which is laudable, but didn't quite understand the implications of what they were writing. However, there are cases with overloaded operators and custom types where it can make a difference.
Some compilers (newer GCCs, Metrowerks, etc) warn on behavior like this with simple types, so it should be avoided.
I think that your question is actually two questions:
What are the implications of returning a const.
What are the implications of returning a reference.
To give you a better answer, I will explain a little more about both concepts.
Regarding the const keyword
The const keyword means that the object cannot be modified through that variable, for instance:
MyObject *o1 = new MyObject;
const MyObject *o2 = o1;
o1->set(...); // Will work and will change the instance variables.
o2->set(...); // Won't compile.
Now, the const keyword can be used in three different contexts:
Assuring the caller of a method that you won't modify the object
For example:
void func(const MyObject &o);
void func(const MyObject *o);
In both cases, any modification made to the object will remain outside the function scope, that's why using the keyword const I assure the caller that I won't be modifying it's instance variables.
Assuring the compiler that a specific method do not mutate the object
If you have a class and some methods that "gets" or "obtains" information from the instance variables without modifying them, then I should be able to use them even if the const keyword is used. For example:
class MyObject
{
...
public:
void setValue(int);
int getValue() const; // The const at the end is the key
};
void funct(const MyObject &o)
{
int val = o.getValue(); // Will compile.
a.setValue(val); // Won't compile.
}
Finally, (your case) returning a const value
This means that the returned object cannot be modified or mutated directly. For example:
const MyObject func();
void func2()
{
int val = func()->getValue(); // Will compile.
func()->setValue(val); // Won't compile.
MyObject o1 = func(); // Won't compile.
MyObject o2 = const_cast<MyObject>(func()); // Will compile.
}
More information about the const keyword: C++ Faq Lite - Const Correctness
Regarding references
Returning or receiving a reference means that the object will not be duplicated. This means that any change made to the value itself will be reflected outside the function scope. For example:
void swap(int &x, int &y)
{
int z = x;
x = y;
y = z;
}
int a = 2; b = 3;
swap(a, b); // a IS THE SAME AS x inside the swap function
So, returning a reference value means that the value can be changed, for instance:
class Foo
{
public:
...
int &val() { return m_val; }
private:
int m_val;
};
Foo f;
f.val() = 4; // Will change m_val.
More information about references: C++ Faq Lite - Reference and value semantics
Now, answering your questions
const int exampleOne();
Means the object returned cannot change through the variable. It's more useful when returning objects.
int& exampleTwo();
Means the object returned is the same as the one inside the function and any change made to that object will be reflected inside the function.
const int& exampleThree();
Means the object returned is the same as the one inside the function and cannot be modified through that variable.
Never thought, that we can return a const value by reference and I don't see the value in doing so..
But, it makes sense if you try to pass a value to a function like this
void func(const int& a);
This has the advantage of telling the compiler to not make a copy of the variable a in memory (which is done when you pass an argument by value and not by reference). The const is here in order to avoid the variable a to be modified.