I want to pass a unique_ptr to a helper function, and I want to make sure that the helper function neither modifies the pointer, nor the pointed object. Without the unique_ptr, the solution is to have
void takePtr(AClass const * const aPtr) {
// Do something with *aPtr.
// We cannot change aPtr, not *aPtr.
}
(Well, technically, AClass const * aPtr is enough.) And I can call this with
AClass * aPtr2 = new AClass(3);
takePtr(aPtr2);
I want to instead use unique_ptr, but cannot figure out how to write this. I tried
void takeUniquePtr(unique_ptr<AClass const> const & aPtr) {
// Access *aPtr, but should not be able to change aPtr, or *aPtr.
}
When I call this with
unique_ptr<AClass> aPtr(new AClass(3));
takeUniquePtr(aPtr);
it does not compile. The error I see is
testcpp/hello_world.cpp:141:21: error: invalid user-defined conversion from ‘std::unique_ptr<AClass>’ to ‘const std::unique_ptr<const AClass>&’ [-fpermissive]
Shouldn't the conversion from unique_ptr<AClass> to unique_ptr<AClass const> be automatic? What am I missing here?
By the way, if I change unique_ptr<AClass const> const & aPtr to unique_ptr<AClass> const & aPtr in the function definition, it compiles, but then I can call functions like aPtr->changeAClass(), which I don't want to allow.
Smart pointers are for managing ownership and lifetime, they allow us (amongst other things) to safely transfer ownership around the various parts of our code.
When you pass a const unique_ptr<T>& to a function (irrelevant of whether T is const or not), what it actually means is that the function promises to never modify the unique_ptr itself (but it could still modify the pointed-to object if T is not const) ie. there will be no possible transfer of ownership whatsoever. You're just using the unique_ptr as a useless wrapper around a naked pointer.
So, as #MarshallClow suggested in a comment, you should just get rid of the wrapper and pass either a naked pointer or a direct reference. What's cool with this is that your code is now semantically clear (your function's signature clearly states that it does not mess with ownership, which was not immediately obvious with a const unique_ptr<...>&) and it solves your "constification" problem at the same time!
Namely:
void someFunction(const AClass* p) { ... }
std::unique_ptr<AClass> ptr(new AClass());
someFunction(ptr.get());
Edit: to address your secondary question "why won't the compiler let me ... cast unique_ptr<A> to unique_ptr<A const>?".
Actually, you can move a unique_ptr<A> to a unique_ptr<A const>:
std::unique_ptr<A> p(new A());
std::unique_ptr<const A> q(std::move(p));
But as you can see this means a transfer of ownership from p to q.
The problem with your code is that you're passing a (reference to) unique_ptr<const A> to a function. Since there is a type discrepancy with unique_ptr<A>, to make it work the compiler needs to instantiate a temporary. But unless you transfer ownership manually by using std::move, the compiler will try to copy your unique_ptr and it can't do that since unique_ptr explicitly forbids it.
Notice how the problem goes away if you move the unique_ptr:
void test(const std::unique_ptr<const int>& p) { ... }
std::unique_ptr<int> p(new int(3));
test(std::move(p));
The compiler is now able to construct a temporary unique_ptr<const A> and move the original unique_ptr<A> without breaking your expectations (since it is now clear that you want to move, not copy).
So, the root of the problem is that unique_ptr only has move semantics not copy semantics, but you'd need the copy semantics to create a temporary and yet keep ownership afterwards. Egg and chicken, unique_ptr just isn't designed that way.
If you now consider shared_ptr which has copy semantics, the problem also disappears.
void test(const std::shared_ptr<const int>& p) { ... }
std::shared_ptr<int> p(new int(3));
test(p);
//^^^^^ Works!
The reason is that the compiler is now able to create a temporary std::shared_ptr<const int> copy (automatically casting from std::shared_ptr<int>) and bind that temporary to a const reference.
I guess this more or less covers it, even though my explanation lacks standardese lingo and is perhaps not as clear as it should be. :)
Got to this old question on const smart pointers.
Above answers ignore the simple template solution.
The very simple template option (option a)
template<class T>
void foo(const unique_ptr<T>& ptr) {
// do something with ptr
}
this solution allows all possible options of unique_ptr to be sent to foo:
const unique_ptr<const int>
unique_ptr<const int>
const unique_ptr<int>
unique_ptr<int>
If you specifically want to avoid for some reason 3 and 4 above, add const to T:
Accept only const/non-const unique_ptr to const! (option b)
template<class T>
void foo(const unique_ptr<const T>& ptr) {
// do something with ptr
}
Side note 1
You may overload "option a" and "option b" if to get different behavior for the cases where you can or cannot alter the pointed value.
Side note 2
If you do not want to make any changes to the pointed value in this function (never! whichever type of parameter we get!) -- do not overload.
With "option b", compiler won't allow to change the value we point at. Job done!
If you want to support all 4 cases, i.e. "option a", the function may still "accidentally" change the value we point to, e.g.
template<class T>
void foo(const unique_ptr<T>& ptr) {
*ptr = 3;
}
however this should not be an issue if at least one caller has T that is actually const, the compiler will not like it in that case and help you get to the problem.
You may add such a caller in unit-test, something like:
foo(make_unique<const int>(7)); // if this line doesn't compile someone
// is changing value inside foo which is
// not allowed!
// do not delete the test, fix foo!
Code snippet: http://coliru.stacked-crooked.com/a/a36795cdf305d4c7
Related
aka. how do I prevent a const& parameter from accidentally binding to a temporary?
We have a class that essentially looks like this:
template<typename T>
struct Observer {
const T* target;
void observe(const T& x) {
target = &x;
}
};
That is, these objects will "hold on" to the const-ref they get passed.
We had a bug where the observe function accidentally got passed a temporary object - something that can never be valid for this case.
What options do we have to prevent accidentally binding to a temporary?
Changing the signature to (const T* px) would work technically (taking the address of a temporary is a compiler warning=error here) it is not very attractive for other reasons.
Side note: Yeah, this will always have potential lifetime management issues, but so far the real thing worked pretty well because of its limited usage pattern - but passing temporaries accidentally has been observed in practice, so we want to possibly address that first.
You can add a rvalue reference overload, and delete it:
void observe(const T&& x) = delete;
Now a compile error will be issued if someone tries to pass a temporary.
About std::move, here is what I can interpret, according to http://en.cppreference.com/w/cpp/utility/move :-
If I want to transfer ownership, I have to call std::move (or in rare case, std::forward).
Responsibility of std::move is calling operator=(A&& other).
The most essential step of the move operation is supposed to be implemented in operator=(A&&).
It is tricky to ensure that operator=(A&&) would be called. It need a special converter.
There are only two converters in the C++ world that can convert variables into xvalue (the &&) : std::move and std::forward.
Question
After adding many of std::move(std::unique_ptr) in my code, I start to worry that for such basic feature like transfer ownership, I have to heavily rely on the standard library (std::).
Do I really have to use std::move to transfer ownership?
Is spamming and hard-code calling std::move in many places of code-base a correct way to go for a high-standard program?
Should std::move be encapsulated?
They are actually a single question, but ask in different perspectives.
Edit
As request, here is my trial & error. It compiled ok.
I have no problem about the code, but I worry about its approach / pattern.
https://ideone.com/y8Pcgf
class T{
public: int value;
public: T(int a=1234){
value = a;
}
};
int main() {
std::unique_ptr<T> t1 = std::unique_ptr<T>(new T(1));
void* databaseNew=operator new [](sizeof(std::unique_ptr<T>));
std::unique_ptr<T>* t1ptr=static_cast<std::unique_ptr<T>*>(databaseNew);
new (t1ptr) std::unique_ptr<T>(std::move(t1));
return 0;
}
Rule of thumb:
If you're in a deduced x-value context, use std::forward:
template<class T>
void foo(T&& t) // T is deduced x-value, so we forward it
{
bar(std::forward<T>(t));
}
Otherwise use std::move
template<class T>
void foo1(std::vector<T> v) // although vector<T> is deduced, it's not an x-value
{
bar(std::move(v)); // so move it
}
template<class T>
void foo2(std::vector<T>&& v) // although vector<T> is deduced, it's not an x-value.
// In this case an r-value reference
{
bar(std::move(v)); // so move it
}
template<class T>
void foo3(std::vector<T>& v) // although vector<T> is deduced, it's not an x-value.
// In this case an l-value reference
{
bar(std::move(v)); // so move it
}
void foo4(std::vector<int> v) // complete type
{
bar(std::move(v)); // so move it
}
void foo5(std::vector<int> const & v) // const reference
{
bar(v); // not much point in moving it. std::move would cast it
// to std::vector<int> const&&, which although is detectable
// decays to std::vector<int> const&
}
which although is detectable... what?
It is permissible, if not necessarily advisable to write code like this:
#include <iostream>
struct X
{
void foo() const &
{
// do one thing...
std::cout << "one thing\n";
}
void foo() const &&
{
// do something else...
std::cout << "or another\n";
}
};
int main()
{
const X x;
x.foo();
std::move(x).foo();
}
const r-value references do exist, it's just that no-one uses them because there is no reasonable use-case.
The need to explicitly move, of which you complain, was actually done on purpose. Before unique_ptr, STL had a horrid construct called auto_ptr. It would move ownership impllicitly, and was borderline unusable unless you really really really knew what you were doing.
To make things more usable, in most cases C++ now requires you to explicitly state that you intend on moving ownership over a container, by using std::move.
In fact, std::move is little more than a cast to an rvalue reference.
There are cases where such an explicit specification is not necessary. For example, if the container from which you take ownership is already an rvalue (e.g. - a temporary object), then no case using std::move is necessary. For example, the following doesn't compile:
std::unique_ptr<int> a;
a = new int;
But the following does, without needing a move:
std::unique_ptr<int> a;
a = std::unique_ptr<int>(new int);
The reason this does not need a call to std::move, despite invoking the move operator, is that the object we move the ownership away from is already a temporary object (i.e. - an rvalue), so no cast is necessary.
Another example is if you call a function that returns a unique_ptr. You might have to call std::move inside the function to get it into the return value, but you do not need to call std::move on the function's return value to get it into the outside unique_ptr. It is already an rvalue, and therefor no cast is necessary.
Consider this class
class Foo
{
public:
Foo()
: r_obj(&nullobj)
{}
void setDataRef(const T& obj)
{
r_obj = &obj;
}
private:
static T nullobj;
const T* r_obj;
};
This forces r_obj to point to something, and I know that the class cannot modify the logical state of whatever it points to. However, now it is perfectly legal to pass a temporary object to setDataRef which is really bad.
If instead using setDataRef(T&), the constness is lost.
Passing a pointer does not force the object to really point to something.
Is it possible to get all three:
Constness
Non-null
Forbid temporary
In old C++ I think this was impossible, but with C++11 we can do:
class Foo
{
public:
Foo()
: r_obj(&nullobj)
{}
void setDataRef(const T& obj)
{
r_obj = &obj;
}
void setDataRef(T&& obj) = delete; // Crucial extra line
private:
static T nullobj;
const T* r_obj;
};
If somebody tries to pass a temporary to setDataRef, overload resolution will prefer the T&& version but because it is deleted, the call is ill-formed. If somebody passes an lvalue, that will bind to the const reference.
Martin's suggestion is very nice and does prevent the caller from passing an rvalue to the function. But that still won't guarantee that the lifetime of the passed object extends beyond the lifetime of the Foo instance.
If the object stores a pointer to the passed object, it would be most intuitive, if a pointer were passed to the setter. Passing a pointer also prevents using an rvalue (because taking an address of an rvalue is not allowed).
Just like you have to document the interface that the passed object must exist as long as Foo instance exists, you can also document that the passed pointer must not be null. Additionally, you can assert it. You could similarly delete the overload for nullptr_t to prevent passing the literal to the setter but that won't prevent passing null pointers of T* type. In my opinion, the advantage of the reference setter is not great.
Of course, neither raw pointer, nor a reference tell the caller anything about ownership, so that must in either case be documented. Instead, I would recommend storing and passing a smart pointer. unique_ptr if Foo should have the ownership (apparently not), shared_ptr if Foo should keep the object alive if it goes out of scope elsewhere, or possibly weak_ptr if Foo should have a failure mode when referred object no longer exists. A smart pointer would be self documenting and intuitive for the user.
In the code below, I made p const because it will never point to any other int during Foo's lifetime. This doesn't compile, as the unique_ptr's copy constructor is called, which is obviously deleted. Are there any solutions besides making p non-const? Thanks.
#include <memory>
using namespace std;
class Foo
{
public:
//x is a large struct in reality
Foo(const int* const x) : p(x) {};
Foo(Foo&& foo) : p(std::move(foo.p)) {};
private:
const unique_ptr<int> p;
};
The semantics of your move constructor are contradictory.
You have declared a const std::unique_ptr which will (uniquely) own the value it is initialised with.
But you've declared a move constructor that should move that value into another object at construction.
So what do you think should happen to the std::unique_ptr in the 'temporary' being move constructed from?
If you want it to be release()ed you've violated its constness.
If you want it to retain its value you've violated the constraint of std::unique which requires no more than one such object to own any given object.
Checkmate.
This problem reveals a subtle limitation of the C++ language. It requires move semantics to leave the copied to and from as valid objects.
There are several quite reasonable proposals for 'destructive move' which would in truth better reflect what most uses of move are doing - take a value to here from there 'invalidating' what was there.
Google them. I haven't made a literature survey so don't want to recommend one.
Your alternatives here are to remove const or cast it way.
I strongly recommend removing it. You can make sure the semantics of your class ensure the appropriate const-ness with no impact and no 'ugly suspect' const_cast.
#include <iostream>
#include <memory>
class Foo
{
public:
Foo(const int x) : p(new int(x)) {};
Foo(Foo&& foo) :
p(std::move(foo.p)) {
};
int get(void)const{
return *(this->p);
}
private:
std::unique_ptr<int> p;
};
Foo getMove(){
return Foo(88);
}
int main(){
Foo bar(getMove());
std::cout<<bar.get()<<std::endl;
return EXIT_SUCCESS;
}
To understand why your code does not compile, reflect how you have declared Foo class and how move semantics is generally implemented.
Declaring a const unique_ptr<T> p, you mean that p itself will be never modified, but you could still modify the pointed-to object because of T is not const.
But move works on an opposite assumption. This feature uses the idea that is allowed stealing resources from objects and leave them in a empty state (if an empty state make sense). If can be useful, think move as a sort of 'destructive' copy for the moved object.
Writing std::move(foo.p), basically you steal the resource pointed by foo.p and leave it in a safe state, that means assign foo.p to NULL. But foo.p was declared as const, so the operation is not permitted.
Please consider that in your case you don't need to declare p as a const unique_ptr<int>. Simply declare it as unique_ptr<int> and make sure that member functions are declared as const and non-member functions take it as
const unique_ptr<int> p& parameter. In this way you are sure that p will never change along the object lifetime (except in case of move operation).
It is because unique_ptr has only the move-constructor, which means the initialization argument to p cannot be const, while p is const. I think what you wanted was to declare
unique_ptr p;
instead of
const unique_ptr p;
class Foo {
public:
// x is a large struct in reality
Foo(const int* const x) : p(x) {};
Foo(Foo&& foo) : p(std::move(foo.p)) {};
private:
const unique_ptr<int> p;
};
Concept of using std::unique_ptr is representing a sole ownership of an object. What you're trying to achieve is having a Foo class own an object (which is expressed by std::unique_ptr) and making it movable (your move constructor) which makes a contradiction. I would stick with std::unique_ptr or make it shared using std::shared_ptr.
You might want to read this:
Smart Pointers: Or who owns you baby?
If you want to prevent transfer of ownership, you can use a const std::unique_ptr<T>. This is not very useful.
If you want to prevent modifying the object it holds, you can use a std::unique_ptr<const T>.
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