This question already has answers here:
What's a use case for overloading member functions on reference qualifiers?
(4 answers)
Closed 10 months ago.
I just discovered this is valid C++:
struct S {
int f() &; // !
int g() const &; // !!
};
int main() {
S s;
s.f();
s.g();
}
IIUC, this is passed to f by reference and to g be passed by const-reference.
How was this useful to anyone?
They are useful for both providing safety and optimizations.
For member functions returning a pointer to something they own (either directly or via view types like std::string_view or std::span), disabling the rvalue overloads can prevent errors:
struct foo {
int* take_ptr_bad() { return &x; }
int* take_ptr() & { return &x; }
int x;
};
foo get_foo();
void bar() {
auto ptr = get_foo().take_ptr_bad();
// ptr is dangling
auto ptr = get_foo().take_ptr();
// does not compile
}
The other is to provide some optimizations. For instance, you might overload a getter function to return an rvalue reference if this is an rvalue to prevent unnecessary copies:
struct foo {
const std::string& get_str() const & {
return s;
}
std::string&& get_str() && {
return std::move(s);
}
std::string s;
};
void sink(std::string);
foo get_foo();
void bar() {
sink(get_foo().get_str());
// moves the string only if the r-value overload is provided.
// otherwise a copy has to be made, even though the foo object
// and transitively the string is temporary.
}
These are how I use the feature, and I'm sure there are more use cases.
Related
This question already has an answer here:
What is the lifetime of reference member default initializer in C++?
(1 answer)
Closed 1 year ago.
I have a question about const std::function& as a member variable.
In the below code, I was expecting to see "2" printed out. But on my compiler (gcc c++17), I saw "1", Why?
using Fn = std::function<bool()>;
class Foo
{
public:
Foo () {}
void bar(){
if(fn_)
std::cout<<"1"<<std::endl;
else
std::cout<<"2"<<std::endl;
}
private:
const Fn& fn_ = nullptr;
};
int main()
{
Foo f;
f.bar();
}
I think what's happening here is that your line
const Fn& fn_ = nullptr;
is essentially doing
const Fn& fn_ = Fn(nullptr);
So that reference is dangling and you're invoking undefined behaviour by accessing it.
If you do it by value instead of by reference, or if you pass in a valid empty Fn object (with sufficient lifetime) to the constructor to bind the ref member to, the output is what you expect.
What would be a valid use case for a signature like this?:
T&& foo();
Or is the rvalue ref only intended for use as argument?
How would one use a function like this?
T&& t = foo(); // is this a thing? And when would t get destructed?
For a free function it doesn't make much sense to return a rvalue reference. If it is a non-static local object then you never want to return a reference or pointer to it because it will be destroyed after the function returns. It can possibly make sense to return a rvalue reference to an object that you passed to the function though. It really depends on the use case for if it makes sense or not.
One thing that can greatly benefit from returning an rvalue reference is a member function of a temporary object. Lets say you have
class foo
{
std::vector<int> bar;
public:
foo(int n) : bar(n) {}
std::vector<int>& get_vec() { return bar; }
};
If you do
auto vec = foo(10).get_vec();
you have to copy because get_vec returns an lvalue. If you instead use
class foo
{
std::vector<int> bar;
public:
foo(int n) : bar(n) {}
std::vector<int>& get_vec() & { return bar; }
std::vector<int>&& get_vec() && { return std::move(bar); }
};
Then vec would be able to move the vector returned by get_vec and you save yourself an expensive copy operation.
T&& t = foo(); // is this a thing? And when would t get destructed?
An rvalue reference is really similar to a lvalue reference. Think about your example like it was normal references:
T& foo();
T& t = foo(); // when is t destroyed?
The answer is that t is still valid to use as long as the object is refers to lives.
The same answer still applies to you rvalue reference example.
But... does it make sense to return an rvalue reference?
Sometimes, yes. But very rarely.
consider this:
std::vector<int> v = ...;
// type is std::tuple<std::vector<int>&&>
auto parameters = std::forward_as_tuple(std::move(v));
// fwd is a rvalue reference since std::get returns one.
// fwd is valid as long as v is.
decltype(auto) fwd = std::get<0>(std::move(parameters));
// useful for calling function in generic context without copying
consume(std::get<0>(std::move(parameters)));
So yes there are example. Here, another interesting one:
struct wrapper {
auto operator*() & -> Heavy& {
return heavy;
}
auto operator*() && -> Heavy&& {
return std::move(heavy);
}
private:
Heavy instance;
};
// by value
void use_heavy(Heavy);
// since the wrapper is a temporary, the
// Heavy contained will be a temporary too.
use_heavy(*make_wrapper());
I think a use case would be to explicitly give permission to "empty" some non-local variable. Perhaps something like this:
class Logger
{
public:
void log(const char* msg){
logs.append(msg);
}
std::vector<std::string>&& dumpLogs(){
return std::move(logs);
}
private:
std::vector<std::string> logs;
};
But I admit I made this up now, I never actually used it and it also can be done like this:
std::vector<std::string> dumpLogs(){
auto dumped_logs = logs;
return dumped_logs;
}
This question already has answers here:
What is "rvalue reference for *this"?
(3 answers)
Closed 4 years ago.
By mistake, I had a & at the end of a prototype (see example below). Neither gcc nor Clang complains about it. I noticed that the symbol generated is not exactly the same.
Example:
class A
{
public:
void fn() &
{
return;
}
};
int main()
{
A a;
a.fn();
return 1;
}
Name of the symbol without &: _ZN1A2fnEv and with &: _ZNR1A2fnEv.
What does it mean ? Do I miss something ?
Thanks,
The & at the end of the member function declaration is a ref qualifier. It applies to the object value on which the member function is called, and constrains that value's value category:
Functions without ref qualifiers can be called on any value.
Functions with & qualifier can only be called on lvalues.
Functions with && qualifier can only be called on rvalues.
The ref qualifier affects overload resolution, e.g. an overload on a mismatched instance value is not viable.
The standard library doesn't use ref qualifiers much (I can only think of std::optional), so let's make up our own example:
struct X {
explicit X(int n) : s_(n, 'a') {}
std::string s_;
const char* f1() const { return s_.c_str(); }
const char* f2() const & { return s_.c_str(); }
const char* f3() const && { return s_.c_str(); }
};
Now consider the following calls:
int main() {
X x(10);
x.f1(); // OK
X(20).f1(); // OK
x.f2(); // OK
X(20).f2(); // ill-formed
x.f3(); // ill-formed
X(20).f3(); // OK
}
The example also demonstrates why this feature may be useful: When a member function returns a reference to some internal part of the object itself, then it is important that that internal reference does not outlast the lifetime of the object. If your member function is unqualified, then you can very easily introduce lifetime bugs. For example:
const char* s = std::string("abcde").c_str(); // dangling pointer!
One way to improve such "internal state access" APIs is to create different return value (categories) for different ref-qualified overloads. To get back to std::optional, the engaged-access essentially boils down to this set of overloads:
struct MyOptional {
T value_; // assume engaged!
T& get() & { return value_; }
T&& get() && { return std::move(value_); }
};
That means that MyOptional::get returns an lvalue when invoked on an lvalue optional, and an rvalue (in fact an xvalue) when invoked on an rvalue. This means that, given MyOptional x;, the binding T& r = x.get(); is allowed, but T& r = MyOptional().get(); is not, and similarly T&& r = x.get(); is disallowed, but T&& r = std::move(x).get() is allowed.
This question already has answers here:
How do I remove code duplication between similar const and non-const member functions?
(21 answers)
C++ template to cover const and non-const method
(7 answers)
Closed 5 years ago.
Is there any advantage using one over the other:
class Foo
{
public:
const int& get() const
{
// stuff here
return myInt;
}
int& get()
{
return const_cast<int&>(static_cast<const Foo*>(this)->get());
}
};
Or
class Foo
{
public:
int& get()
{
// stuff here
return myInt;
}
const int& get() const
{
return const_cast<Foo*>(this)->get();
}
};
I only used the first one, but I just saw the second one used somewhere, so I am wondering.
The comment // stuff here could be a non-trivial check like retrieving the index of a table in order to return a ref on a member of the table (for example: myInt = myTable[myComputedIndex];) so I cannot just make it public. Thus table and any member are not const.
If you have to make a function that is const-agnostic, and avoids duplication, one neat way to do it is delegating implementation to a template, for example
class Foo {
private:
int my_int;
template <typename ThisPtr>
static auto& get(ThisPtr this_ptr) {
return this_ptr->my_int;
}
public:
int& get() {
return get(this);
}
const int& get() const {
return get(this);
}
};
This way you are free from the fear associated with using const_cast, mutable and other stuff that goes into trying to reduce code duplication in cases like this. If you get something wrong, the compiler will let you know.
Ignoring the issue of whether you really need a getter, the best solution when duplicating functionality in both a const and non-const method is to have the non-const method call the const method and cast away the const-ness of the result (i.e. the first of the two alternatives you present in the question).
The reason is simple: if you do it the other way around (with the logic in the non-const method), you could accidentally end up modifying a const object, and the compiler won't catch it at compile time (because the method is not declared const) - this will have undefined behaviour.
Of course this is only a problem if the "getter" is not actually a getter (i.e. if it is doing something more complicated than just returning a reference to a private field).
Also, if you are not constrained to C++11, the template-based solution presented by Curious in their answer is another way of avoiding this problem.
Is there any advantage using one over the other: ...
No, both are bad because they violate the data encapsulation principle.
In your example you should rather make myInt a public member.
There's no advantage to have getters for such case at all.
If you really want (need) getter and setter functions these should look like this:
class Foo
{
private:
mutable int myInt_;
// ^^^^^^^ Allows lazy initialization from within the const getter,
// simply omit that if you dont need it.
public:
void myInt(int value)
{
// Do other stuff ...
myInt = value;
// Do more stuff ...
}
const int& myInt() const
{
// Do other stuff ...
return myInt_;
}
}
You don't say where myInt comes from, the best answer depends on that.
There are 2+1 possible scenarios:
1) The most common case is that myInt comes from a pointer internal to the class.
Assuming that, this is the best solution which avoids both code duplication and casting.
class Foo{
int* myIntP;
...
int& get_impl() const{
... lots of code
return *myIntP; // even if Foo instance is const, *myInt is not
}
public:
int& get(){return get_impl();}
const int& get() const{return get_impl();}
};
This case above applies to pointer array, and (most) smart pointers.
2) The other common case is that myInt is a reference or a value member, then the previous solution doesn't work.
But it is also the case where a getter is not needed at all.
Don't use a getter in that case.
class Foo{
public:
int myInt; // or int& myInt;
};
done! :)
3) There is a third scenario, pointed by #Aconcagua, that is the case of an internal fixed array. In that case it is a toss-up, it really depends what you are doing, if finding the index is really the problem, then that can be factored away. It is not clear however what is the application:
class Foo{
int myInts[32];
...
int complicated_index() const{...long code...}
public:
int& get(){return myInts[complicated_index()];}
const int& get() const{return myInts[complicated_index()];}
};
My point is, understand the problem and don´t over engineer. const_cast or templates are not needed to solve this problem.
complete working code below:
class Foo{
int* myIntP;
int& get_impl() const{
return *myIntP; // even if Foo instance is const, *myInt is not
}
public:
int& get(){return get_impl();}
const int& get() const{return get_impl();}
Foo() : myIntP(new int(0)){}
~Foo(){delete myIntP;}
};
#include<cassert>
int main(){
Foo f1;
f1.get() = 5;
assert( f1.get() == 5 );
Foo const f2;
// f2.get() = 5; // compile error
assert( f2.get() == 0 );
return 0;
}
As you intend access to more complex internal structures (as clarified via your edit; such as providing an operator[](size_t index) for internal arrays as std::vector does), then you will have to make sure that you do not invoke undefined behaviour by modifying a potentially const object.
The risk of doing so is higher in the second approach:
int& get()
{
// stuff here: if you modify the object, the compiler won't warn you!
// but you will modify a const object, if the other getter is called on one!!!
return myInt;
}
In the first variant, you are safe from (unless you do const_cast here, too, which now would really be bad...), which is the advantage of this approach:
const int& get() const
{
// stuff here: you cannot modify by accident...
// if you try, the compiler will complain about
return myInt;
}
If you actually need to modify the object in the non-const getter, you cannot have a common implementation anyway...
Modifying a const object through a non-const access path [...] results in undefined behavior.
(Source: http://en.cppreference.com/w/cpp/language/const_cast)
This means that the first version can lead to undefined behavior if myInt is actually a const member of Foo:
class Foo
{
int const myInt;
public:
const int& get() const
{
return myInt;
}
int& get()
{
return const_cast<int&>(static_cast<const Foo*>(this)->get());
}
};
int main()
{
Foo f;
f.get() = 10; // this compiles, but it is undefined behavior
}
The second version would not compile, because the non-const version of get would be ill-formed:
class Foo
{
int const myInt;
public:
int& get()
{
return myInt;
// this will not compile, you cannot return a const member
// from a non-const member function
}
const int& get() const
{
return const_cast<Foo*>(this)->get();
}
};
int main()
{
Foo f;
f.get() = 10; // get() is ill-formed, so this does not compile
}
This version is actually recommended by Scott Meyers in Effective C++ under Avoid Duplication in const and Non-const Member Function.
I made a wrapper around an object in my code that should modify accesses to the object. I choose to use an object here for testing instead of a functor that would have the same functionality. Basically: The wrapper receives a reference to the object and forwards all indexed accesses to the object (after some possible manipulation)
Now comes the problem: The accessor discards constness of the wrapped object.
Minimal Example
struct Foo
{
std::array<int, 2> data;
const int& operator()(int idx) const{
return data[idx];
}
int& operator()(int idx){
return data[idx];
}
};
struct Bar
{
Foo& ref;
Bar(Foo& r):ref(r){}
int& operator()(int idx) const{
return ref(idx);
}
};
template< typename T >
void test(const T& data){
data(1) = 4;
std::cout << data(1);
}
void main(){
Foo f;
test(f);
// Above call does not compile (as expected)
// (assignment of read-only location)
Bar b(f);
test(b); // This does compile and works (data is modified)
}
Declaring the ()-operator of Bar (the wrapper) "const", I'd expect to be all member accesses "const" to. So it shouldn't be possible to return an "int&" but only a "const int&"
However gcc4.7 happily compiles the code and the const is ignored. Is this the correct behavior? Where is this specified?
Edit:
On a related issue: If use typedefs in Foo like:
struct Foo
{
using Ref = int&;
using ConstRef = const int&; //1
using ConstRef = const Ref; //2
int* data; // Use int* to have same issue as with refs
ConstRef operator()(int idx) const{
return data[idx]; // This is possible due to the same "bug" as with the ref in Bar
}
Ref operator()(int idx){
return data[idx];
}
};
I noticed that //1 does work as expected but //2 does not. Return value is still modifiable. Shouldn't they be the same?
Yes, this is correct behaviour. The type of ref is Foo &. Adding const to a reference type1 does nothing—a reference is already immutable, anyway. It's like having a member int *p. In a const member function, its type is treated as int * const p, not as int const * p.
What you need to do is add const manually inside the const overload if you want it there:
struct Bar
{
Foo& ref;
Bar(Foo& r):ref(r){}
int& operator()(int idx) const{
return const_cast<const Foo&>(ref)(idx);
}
};
To address the question edit: no, the typedefs are not the same. const int & is a reference to a (constant int). const Ref is a constant Ref, that is, a constant (reference to int); parentheses used in mathematical sense.
1 I am talking about the reference type itself. Not to be confused with adding const to the type to which the reference refers.
Yeah, it is expected behaviour. The reason is that const for your method says only that reference wont be change not the referenced object. Reference is always unchanged so it is always true. Take a look at this code with pointer:
int i;
struct Bar
{
int* pi;
Foo& ref;
Bar(Foo& r):ref(r){}
int& operator()(int idx) const{
*pi = 4; // we can change pointed object
pi = &i; // Compile error: we can't change the pointer.
return ref(idx);
}
};