I am new to C++11. In fact until recently, I programmed only using dynamic allocation, in a way similar to Java, e.g.
void some_function(A *a){
a->changeInternalState();
}
A *a = new A();
some_function(a);
delete a;
// example 2
some_function( new A() ); // suppose there is **no** memory leak.
Now I want to reproduce similar code with C++11, but without pointers.
I need to be able to pass newly created class class A directly to function useA(). There seems to be a problem if I want to do so with non-const normal reference and It works if I do it with rvalue reference.
Here is the code:
#include <stdio.h>
class A{
public:
void print(){
++p; // e.g. change internal state
printf("%d\n", p);
}
int p;
};
// normal reference
void useA(A & x){
x.print();
}
// rvalue reference
void useA(A && x){
useA(x);
}
int main(int argc, char** argv)
{
useA( A{45} ); // <--- newly created class
A b{20};
useA(b);
return 0;
}
It compiles and executes correctly, but I am not sure, if this is the correct acceptable way to do the work?
Are there some best practices for this kind of operations?
Normally you would not design the code so that a temporary object gets modified. Then you would write your print function as:
void useA(A const & x){
x.print();
}
and declare A::print as const. This binds to both rvalues and lvalues. You can use mutable for class member variables which might change value but without the object logically changing state.
Another plan is to keep just A &, but write:
{ A temp{45}; useA(temp); }
If you really do want to modify a temporary object, you can write the pair of lvalue and rvalue overloads as you have done in your question. I believe this is acceptable practice for that case.
The best thing about C++11 move semantics is that most of the time, you get them "for free" without having to explicitly add any &&s or std::move()s in your code. Usually, you only need to use these things explicitly if you're writing code that does manual memory management, such as the implementation of a smart pointer or a container class, where you would have had to write a custom destructor and copy constructor anyway.
In your example, A is just an int. For ints, a move is no different from a copy, because there's no opportunity for optimization even if the int happens to be a disposable temporary. Just provide a single useA() function that takes an ordinary reference. It'll have the same behavior.
Related
#include <utility>
class SomeObject {
// ...Object Definition
};
void B(SomeObject& so)
{
SomeObject movedTo = std::move(so);
}
void A(SomeObject& so)
{
B(so);
}
int main()
{
SomeObject movedFrom;
A(movedFrom);
return 0;
}
For example, now I have two functions A and B. Function A may first do something, then pass the argument so to function B. In function B, I will move the passed argument so. What confused me a lot is that there is another way to do this:
#include <utility>
class SomeObject {
// ...Object Definition
};
void B(SomeObject&& so)
{
SomeObject movedTo = std::move(so);
}
void A(SomeObject&& so)
{
B(std::move(so));
}
int main()
{
SomeObject movedFrom;
A(std::move(movedFrom));
return 0;
}
In the second version, the parameter of function A and B are rvalue references. Both of these codes compiles, and both of them work well. So, which one is the better practice of doing such kind of thing?
void B(SomeObject& so)
{
SomeObject movedTo = std::move(so);
This is a bad design. Don't move from an lvalue reference parameter. That is going to miselead programmers who make reasonable assumptions based on the parameter type and won't expect the argument that they pass to be moved from.
In the second version, the parameter of function A and B are rvalue references.
This is much better. It is reasonable to expect an rvalue reference to be moved from.
So, which one is the better practice of doing such kind of thing?
The second one, without a doubt.
What is the best practice if I want to forward
You aren't "forwarding" in the common use of the word. What is typically called forwarding is to copy from an lvalue and move from an rvalue. You can achieve that by using a value parameter instead of a reference:
void B(SomeObject so)
{
SomeObject movedTo = std::move(so);
}
This way the caller can move an object argument with low cost, or copy it when they don't want their argument to be moved from.
SomeObject so;
B(so); // copy
B(std::move(so)); // move
Although it took me a while to get used to it, I now grew the habit of letting my functions take shared pointer parameters by lvalue-reference to const rather than by value (unless I need to modify the original arguments, of course, in which case I take them by lvalue-reference to non-const):
void foo(std::shared_ptr<widget> const& pWidget)
// ^^^^^^
{
// work with pWidget...
}
This has the advantage of avoiding an unnecessary copy of a shared pointer, which would mean thread-safely increasing the reference counting and potentially incurring in undesired overhead.
Now I've been wondering whether it is sane to adopt a somewhat symmetrical habit for retrieving shared pointers that are returned by value from functions, like at the end of the following code snippet:
struct X
{
// ...
std::shared_ptr<Widget> bar() const
{
// ...
return pWidget;
}
// ...
std::shared_ptr<Widget> pWidget;
};
// ...
// X x;
std::share_ptr<Widget> const& pWidget = x.bar();
// ^^^^^^
Are there any pitfalls with adopting such a coding habit? Is there any reason why I should prefer, in general, assigning a returned shared pointer to another shared pointer object rather than binding it to a reference?
This is just a remake of the old question of whether capturing a const reference to a temporary is more efficient than creating a copy. The simple answer is that it isn't. In the line:
// std::shared_ptr<Widget> bar();
std::shared_ptr<Widget> const & pWidget = bar();
The compiler needs to create a local unnamed variable (not temporary), initailize that with the call to bar() and then bind the reference to it:
std::shared_ptr<Widget> __tmp = bar();
std::shared_ptr<Widget> const & pWidget = __tmp;
In most cases it will avoid the creation of the reference and just alias the original object in the rest of the function, but at the end of the day whether the variable is called pWidget or __tmp and aliased won't give any advantage.
On the contrary, for the casual reader, it might look like bar() does not create an object but yield a reference to an already existing std::shared_ptr<Widget>, so the maintainer will have to seek out where bar() is defined to understand whether pWidget can be changed outside of the scope of this function.
Lifetime extension through binding to a const reference is a weird feature in the language that has very little practical use (namely when the reference is of a base and you don't quite care what the exact derived type returned by value is, i.e. ScopedGuard).
You may have the optimization backwards:
struct X
{
// ...
std::shared_ptr<Widget> const& bar() const
{
// ...
return pWidget;
}
// ...
std::shared_ptr<Widget> pWidget;
};
// ...
// X x;
std::share_ptr<Widget> pWidget = x.bar();
As bar is returning a member variable, it must take a copy of the shared_ptr in your version. If you return the member variable by reference the copy can be avoided.
This doesn't matter in both your original version and the version shown above, but would come up if you called:
x.bar()->baz()
In your version a new shared_ptr would be created, and then baz would be called.
In my version baz is called directly on the member copy of the shared_ptr, and the atomic reference increment/decrement is avoided.
Of course the cost of the shared_ptr copy constructor (atomic increment) is very small, and not even noticable in all but the most performance-sensetive applications. If you are writing a performance sensetive application than the better option would be to manage memory manually with a memory pool architecture and then to (carefully) use raw pointers instead.
Adding on top of what David Rodríguez - dribeas said namely, binding to a const reference doesn't save you from making the copy and the counter is incremented anyway, the following code illustrates this point:
#include <memory>
#include <cassert>
struct X {
std::shared_ptr<int> p;
X() : p{new int} {}
std::shared_ptr<int> bar() { return p; }
};
int main() {
X x;
assert(x.p.use_count() == 1);
std::shared_ptr<int> const & p = x.bar();
assert(x.p.use_count() == 2);
return 0;
}
I understand that having a const method in C++ means that an object is read-only through that method, but that it may still change otherwise.
However, this code apparently changes an object through a const reference (i.e. through a const method).
Is this code legal in C++?
If so: Is it breaking the const-ness of the type system? Why/why not?
If not: Why not?
Note 1: I have edited the example a bit, so answers might be referring to older examples.
Edit 2: Apparently you don't even need C++11, so I removed that dependency.
#include <iostream>
using namespace std;
struct DoBadThings { int *p; void oops() const { ++*p; } };
struct BreakConst
{
int n;
DoBadThings bad;
BreakConst() { n = 0; bad.p = &n; }
void oops() const { bad.oops(); } // can't change itself... or can it?
};
int main()
{
const BreakConst bc;
cout << bc.n << endl; // 0
bc.oops(); // O:)
cout << bc.n << endl; // 1
return 0;
}
Update:
I have migrated the lambda to the constructor's initialization list, since doing so allows me to subsequently say const BreakConst bc;, which -- because bc itself is now const (instead of merely the pointer) -- would seem to imply (by Stroustrup) that modifying bc in any way after construction should result in undefined behavior, even though the constructor and the caller would have no way of knowing this without seeing each others' definitions.
The oops() method isn't allowed to change the constness of the object. Furthermore it doesn't do it. Its your anonymous function that does it. This anonymous function isn't in the context of the object, but in the context of the main() method which is allowed to modify the object.
Your anonymous function doesn't change the this pointer of oops() (which is defined as const and therefore can't be changed) and also in no way derives some non-const variable from this this-pointer. Itself doesn't have any this-pointer. It just ignores the this-pointer and changes the bc variable of the main context (which is kind of passed as parameter to your closure). This variable is not const and therefore can be changed. You could also pass any anonymous function changing a completely unrelated object. This function doesn't know, that its changing the object that stores it.
If you would declare it as
const BreakConst bc = ...
then the main function also would handle it as const object and couldn't change it.
Edit:
In other words: The const attribute is bound to the concrete l-value (reference) accessing the object. It's not bound to the object itself.
You code is correct, because you don't use the const reference to modify the object. The lambda function uses completely different reference, which just happen to be pointing to the same object.
In the general, such cases does not subvert the type system, because the type system in C++ does not formally guarantee, that you can't modify the const object or the const reference. However modification of the const object is the undefined behaviour.
From [7.1.6.1] The cv-qualifiers:
A pointer or reference to a cv-qualified type need not actually point
or refer to a cv-qualified object, but it is treated as if it does; a
const-qualified access path cannot be used to modify an object even if
the object referenced is a non-const object and can be modified through
some other access path.
Except that any class member declared mutable (7.1.1) can be modified,
any attempt to modify a const object during its lifetime (3.8) results
in undefined behavior.
I already saw something similar. Basically you invoke a cost function that invoke something else that modifies the object without knowing it.
Consider this as well:
#include <iostream>
using namespace std;
class B;
class A
{
friend class B;
B* pb;
int val;
public:
A(B& b);
void callinc() const;
friend ostream& operator<<(ostream& s, const A& a)
{ return s << "A value is " << a.val; }
};
class B
{
friend class A;
A* pa;
public:
void incval() const { ++pa->val; }
};
inline A::A(B& b) :pb(&b), val() { pb->pa = this; }
inline void A::callinc() const { pb->incval(); }
int main()
{
B b;
const A a(b); // EDIT: WAS `A a(b)`
cout << a << endl;
a.callinc();
cout << a << endl;
}
This is not C++11, but does the same:
The point is that const is not transitive.
callinc() doesn't change itself a and incval doesn't change b.
Note that in main you can even declare const A a(b); instead of A a(b); and everything compile the same.
This works from decades, and in your sample you're just doing the same: simply you replaced class B with a lambda.
EDIT
Changed the main() to reflect the comment.
The issue is one of logical const versus bitwise const. The compiler
doesn't know anything about the logical meaning of your program, and
only enforces bitwise const. It's up to you to implement logical const.
This means that in cases like you show, if the pointed to memory is
logically part of the object, you should refrain from modifying it in a
const function, even if the compiler will let you (since it isn't part
of the bitwise image of the object). This may also mean that if part of
the bitwise image of the object isn't part of the logical value of the
object (e.g. an embedded reference count, or cached values), you make it
mutable, or even cast away const, in cases where you modify it without
modifying the logical value of the object.
The const feature merely helps against accidental misuse. It is not designed to prevent dedicated software hacking. It is the same as private and protected membership, someone could always take the address of the object and increment along the memory to access class internals, there is no way to stop it.
So, yes you can get around const. If nothing else you can simply change the object at the memory level but this does not mean const is broken.
Sometimes we like to take a large parameter by reference, and also to make the reference const if possible to advertize that it is an input parameter. But by making the reference const, the compiler then allows itself to convert data if it's of the wrong type. This means it's not as efficient, but more worrying is the fact that I think I am referring to the original data; perhaps I will take it's address, not realizing that I am, in effect, taking the address of a temporary.
The call to bar in this code fails. This is desirable, because the reference is not of the correct type. The call to bar_const is also of the wrong type, but it silently compiles. This is undesirable for me.
#include<vector>
using namespace std;
int vi;
void foo(int &) { }
void bar(long &) { }
void bar_const(const long &) { }
int main() {
foo(vi);
// bar(vi); // compiler error, as expected/desired
bar_const(vi);
}
What's the safest way to pass a lightweight, read-only reference? I'm tempted to create a new reference-like template.
(Obviously, int and long are very small types. But I have been caught out with larger structures which can be converted to each other. I don't want this to silently happen when I'm taking a const reference. Sometimes, marking the constructors as explicit helps, but that is not ideal)
Update: I imagine a system like the following: Imagine having two functions X byVal(); and X& byRef(); and the following block of code:
X x;
const_lvalue_ref<X> a = x; // I want this to compile
const_lvalue_ref<X> b = byVal(); // I want this to fail at compile time
const_lvalue_ref<X> c = byRef(); // I want this to compile
That example is based on local variables, but I want it to also work with parameters. I want to get some sort of error message if I'm accidentally passing a ref-to-temporary or a ref-to-a-copy when I think I'll passing something lightweight such as a ref-to-lvalue. This is just a 'coding standard' thing - if I actually want to allow passing a ref to a temporary, then I'll use a straightforward const X&. (I'm finding this piece on Boost's FOREACH to be quite useful.)
Well, if your "large parameter" is a class, the first thing to do is ensure that you mark any single parameter constructors explicit (apart from the copy constructor):
class BigType
{
public:
explicit BigType(int);
};
This applies to constructors which have default parameters which could potentially be called with a single argument, also.
Then it won't be automatically converted to since there are no implicit constructors for the compiler to use to do the conversion. You probably don't have any global conversion operators which make that type, but if you do, then
If that doesn't work for you, you could use some template magic, like:
template <typename T>
void func(const T &); // causes an undefined reference at link time.
template <>
void func(const BigType &v)
{
// use v.
}
If you can use C++11 (or parts thereof), this is easy:
void f(BigObject const& bo){
// ...
}
void f(BigObject&&) = delete; // or just undefined
Live example on Ideone.
This will work, because binding to an rvalue ref is preferred over binding to a reference-to-const for a temporary object.
You can also exploit the fact that only a single user-defined conversion is allowed in an implicit conversion sequence:
struct BigObjWrapper{
BigObjWrapper(BigObject const& o)
: object(o) {}
BigObject const& object;
};
void f(BigObjWrapper wrap){
BigObject const& bo = wrap.object;
// ...
}
Live example on Ideone.
This is pretty simple to solve: stop taking values by reference. If you want to ensure that a parameter is addressable, then make it an address:
void bar_const(const long *) { }
That way, the user must pass a pointer. And you can't get a pointer to a temporary (unless the user is being terribly malicious).
That being said, I think your thinking on this matter is... wrongheaded. It comes down to this point.
perhaps I will take it's address, not realizing that I am, in effect, taking the address of a temporary.
Taking the address of a const& that happens to be a temporary is actually fine. The problem is that you cannot store it long-term. Nor can you transfer ownership of it. After all, you got a const reference.
And that's part of the problem. If you take a const&, your interface is saying, "I'm allowed to use this object, but I do not own it, nor can I give ownership to someone else." Since you do not own the object, you cannot store it long-term. This is what const& means.
Taking a const* instead can be problematic. Why? Because you don't know where that pointer came from. Who owns this pointer? const& has a number of syntactic safeguards to prevent you from doing bad things (so long as you don't take its address). const* has nothing; you can copy that pointer to your heart's content. Your interface says nothing about whether you are allowed to own the object or transfer ownership to others.
This ambiguity is why C++11 has smart pointers like unique_ptr and shared_ptr. These pointers can describe real memory ownership relations.
If your function takes a unique_ptr by value, then you now own that object. If it takes a shared_ptr, then you now share ownership of that object. There are syntactic guarantees in place that ensure ownership (again, unless you take unpleasant steps).
In the event of your not using C++11, you should use Boost smart pointers to achieve similar effects.
You can't, and even if you could, it probably wouldn't help much.
Consider:
void another(long const& l)
{
bar_const(l);
}
Even if you could somehow prevent the binding to a temporary as input to
bar_const, functions like another could be called with the reference
bound to a temporary, and you'd end up in the same situation.
If you can't accept a temporary, you'll need to use a reference to a
non-const, or a pointer:
void bar_const(long const* l);
requires an lvalue to initialize it. Of course, a function like
void another(long const& l)
{
bar_const(&l);
}
will still cause problems. But if you globally adopt the convention to
use a pointer if object lifetime must extend beyond the end of the call,
then hopefully the author of another will think about why he's taking
the address, and avoid it.
I think your example with int and long is a bit of a red herring as in canonical C++ you will never pass builtin types by const reference anyway: You pass them by value or by non-const reference.
So let's assume instead that you have a large user defined class. In this case, if it's creating temporaries for you then that means you created implicit conversions for that class. All you have to do is mark all converting constructors (those that can be called with a single parameter) as explicit and the compiler will prevent those temporaries from being created automatically. For example:
class Foo
{
explicit Foo(int bar) { }
};
(Answering my own question thanks to this great answer on another question I asked. Thanks #hvd.)
In short, marking a function parameter as volatile means that it cannot be bound to an rvalue. (Can anybody nail down a standard quote for that? Temporaries can be bound to const&, but not to const volatile & apparently. This is what I get on g++-4.6.1. (Extra: see this extended comment stream for some gory details that are way over my head :-) ))
void foo( const volatile Input & input, Output & output) {
}
foo(input, output); // compiles. good
foo(get_input_as_value(), output); // compile failure, as desired.
But, you don't actually want the parameters to be volatile. So I've written a small wrapper to const_cast the volatile away. So the signature of foo becomes this instead:
void foo( const_lvalue<Input> input, Output & output) {
}
where the wrapper is:
template<typename T>
struct const_lvalue {
const T * t;
const_lvalue(const volatile T & t_) : t(const_cast<const T*>(&t_)) {}
const T* operator-> () const { return t; }
};
This can be created from an lvalue only
Any downsides? It might mean that I accidentally misuse an object that is truly volatile, but then again I've never used volatile before in my life. So this is the right solution for me, I think.
I hope to get in the habit of doing this with all suitable parameters by default.
Demo on ideone
#include <iostream>
#include <memory>
class test
{
private:
int x , y;
public:
test(int a , int b):x(a),y(b){}
void fun()
{
std::cout<< x<<" "<<y<<" "<<std::endl;
}
};
void show(std::auto_ptr<test> t1)
{
t1->fun();
}
int main()
{
show(new test(3,4));
}
I am getting a compilation error , please tell me what's wrong in this code?Thanks in advance.
Whenever you dynamically allocate an object, you should create a named smart pointer that immediately takes ownership of the object, then use that named smart pointer. For example,
std::auto_ptr<test> ptr(new test(3, 4));
show(ptr);
You cannot pass new test(3, 4) directly to the function because std::auto_ptr objects must be explicitly constructed; it would be quite unexpected if a smart pointer took ownership of an object implicitly.
That said, this is rather unusual anyway because when you call show(), the auto_ptr is copied and when auto_ptr is "copied," the original loses ownership and the copy gains ownership (so, after show() is called, you will find that ptr no longer has ownership of the object.
James explained how to resolve the problem.
But the reason auto_ptr was designed so that you can not do this:
show(new test(3,4));
Is because this is a bad idea.
Even this (if it were allowed):
show(std::auto_ptr<test>(new test(3,4)));
Would be a bad idea.
So you ask why.
Well in the normal situation not a big deal.
Bu what happens when you have a function that takes more than one parameter.
show2(std::auto_ptr<test>(new test(3,4)), SomeObject());
Now the standard gurantees that all parameters will be fully evaluated before the call (even the construction of the auto_ptr). But it does not guarantee the evaluation order nor that the evaluation will not be interleaved.
Thus it is possible for this evaluation:
// Phsedu code for parameter evaluation
test* tmp1 = new test(3,4);
SomeObject const& tmp2 = SomeObject();
std::auto_ptr<test> const& tmp3(tmp1);
call(tmp3, tmp1)
This order is bad. Because if the constructor of SomeObject throws an exception you will leak tmp1 as it has not yet been assigned to the std::auto_ptr.
This is why we auto_ptr was designed so that you have to give it a named variable.
std::auto_ptr<test> tmp3(new test(3,4));
SomeObject tmp1;
call(tmp3, tmp1)
Now if SomObject constructor throws the test object will be tidied up.