How can I pass a std::unique_ptr into a function? Lets say I have the following class:
class A
{
public:
A(int val)
{
_val = val;
}
int GetVal() { return _val; }
private:
int _val;
};
The following does not compile:
void MyFunc(unique_ptr<A> arg)
{
cout << arg->GetVal() << endl;
}
int main(int argc, char* argv[])
{
unique_ptr<A> ptr = unique_ptr<A>(new A(1234));
MyFunc(ptr);
return 0;
}
Why can I not pass a std::unique_ptr into a function? Surely this is the primary purpose of the construct? Or did the C++ committee intend for me to fall back to raw C-style pointers and pass it like this:
MyFunc(&(*ptr));
And most strangely of all, why is this an OK way of passing it? It seems horribly inconsistent:
MyFunc(unique_ptr<A>(new A(1234)));
There's basically two options here:
Pass the smart pointer by reference
void MyFunc(unique_ptr<A> & arg)
{
cout << arg->GetVal() << endl;
}
int main(int argc, char* argv[])
{
unique_ptr<A> ptr = unique_ptr<A>(new A(1234));
MyFunc(ptr);
}
Move the smart pointer into the function argument
Note that in this case, the assertion will hold!
void MyFunc(unique_ptr<A> arg)
{
cout << arg->GetVal() << endl;
}
int main(int argc, char* argv[])
{
unique_ptr<A> ptr = unique_ptr<A>(new A(1234));
MyFunc(move(ptr));
assert(ptr == nullptr)
}
You're passing it by value, which implies making a copy. That wouldn't be very unique, would it?
You could move the value, but that implies passing ownership of the object and control of its lifetime to the function.
If the lifetime of the object is guaranteed to exist over the lifetime of the call to MyFunc, just pass a raw pointer via ptr.get().
Why can I not pass a unique_ptr into a function?
You cannot do that because unique_ptr has a move constructor but not a copy constructor. According to the standard, when a move constructor is defined but a copy constructor is not defined, the copy constructor is deleted.
12.8 Copying and moving class objects
...
7 If the class definition does not explicitly declare a copy constructor, one is declared implicitly. If the class definition declares a move constructor or move assignment operator, the implicitly declared copy constructor is defined as deleted;
You can pass the unique_ptr to the function by using:
void MyFunc(std::unique_ptr<A>& arg)
{
cout << arg->GetVal() << endl;
}
and use it like you have:
or
void MyFunc(std::unique_ptr<A> arg)
{
cout << arg->GetVal() << endl;
}
and use it like:
std::unique_ptr<A> ptr = std::unique_ptr<A>(new A(1234));
MyFunc(std::move(ptr));
Important Note
Please note that if you use the second method, ptr does not have ownership of the pointer after the call to std::move(ptr) returns.
void MyFunc(std::unique_ptr<A>&& arg) would have the same effect as void MyFunc(std::unique_ptr<A>& arg) since both are references.
In the first case, ptr still has ownership of the pointer after the call to MyFunc.
Why can I not pass a unique_ptr into a function?
You can, but not by copy - because std::unique_ptr<> is not copy-constructible.
Surely this is the primary purpose of the construct?
Among other things, std::unique_ptr<> is designed to unequivocally mark unique ownership (as opposed to std::shared_ptr<> ).
And most strangely of all, why is this an OK way of passing it?
Because in that case, there is no copy-construction.
As MyFunc doesn't take ownership, it would be better to have:
void MyFunc(const A* arg)
{
assert(arg != nullptr); // or throw ?
cout << arg->GetVal() << endl;
}
or better
void MyFunc(const A& arg)
{
cout << arg.GetVal() << endl;
}
If you really want to take ownership, you have to move your resource:
std::unique_ptr<A> ptr = std::make_unique<A>(1234);
MyFunc(std::move(ptr));
or pass directly a r-value reference:
MyFunc(std::make_unique<A>(1234));
std::unique_ptr doesn't have copy on purpose to guaranty to have only one owner.
Since unique_ptr is for unique ownership, if you want to pass it as argument try
MyFunc(move(ptr));
But after that the state of ptr in main will be nullptr.
To piggyback the existing answers, C++ smart pointers are strongly related to the concept of ownership. Your code should clearly express your inensions related to passing or not the ownership to another component, i.e. function, thread or so, that's why there are unique, shared and weak pointers. The unique pointer already suggests that only one component has the ownership of that pointer at one moment, so that unique ownership cannot be shared, only moved. Namely the owner that currently owns the pointer will destroy it at its own will when getting out of context, usually at the end of the block or in a destructor. Passing an object to another function might imply sharing or moving the ownership. If you are sure that the owner don't get out of the context while calling the function by reference, calling by reference is possible, but it's just ugly. It adds some preconditions and postconditions and will increase the immobility of your code while it also breaks the smartness of the pointer which tuns into a more or less raw pointer. For example, changing the "function" to start and execute its own stuff in another thread is not longer possible. As passing by reference is still an option in some very contained parts of your code, i.e. looking for saving extra overhead of moving back and forth from unique to shared pointers, I would highly avoid it, especially in public interfaces.
Passing std::unique_ptr<T> as value to a function is not working because, as you guys mention, unique_ptr is not copyable.
What about this?
std::unique_ptr<T> getSomething()
{
auto ptr = std::make_unique<T>();
return ptr;
}
this code is working
Related
Lets consider the following piece of code:
template<typename T>
void f(std::unique_ptr<T>&& uptr) { /*...*/ }
In another function:
void g()
{
std::unique_ptr<ANY_TYPE> u_ptr = std::make_unique<ANY_TYPE>();
f(std::move(u_ptr));
X: u_ptr->do_sth(); // it works, I don't understand why. Details below.
}
I don't understand why u_ptr in line X is still alive.
After all I forced him to be moved (std::move).
---EDIT---
Ok, so now:
The code is still working:
class T{
public:
T(){}
void show(){
std::cout << "HEJ!\n";
}
};
void f(std::unique_ptr<T> ref){
ref->show();
}
int main()
{
std::unique_ptr<T> my;
my->show();
f(std::move(my));
my->show(); // How is it possible. Now, f takes unique_ptr by value
return 0;
}
You didn't show us that code to function f, but presumably it didn't move the pointer, even though it had permission to.
You passed the unique_ptr by reference. If function invocation actually moved it, then the function couldn't use it because it would be gone before the function had a chance to.
If you want function invocation to actually move the pointer, you need to pass the pointer by value, not be reference. That value would be a unique_ptr for it to be moved into. In that case, you should declare the function as taking a std::unique_ptr<T> instead of a std::unique_ptr<T>&&. Then you can actually invoke the move constructor when you call the function.
Update: With your latest change, the unique_ptr would no longer reference any valid object due to the move construction. You just never check that it does. Invoking a non-virtual method that doesn't access any member variables can work just the same whether the object is valid or destroyed because it doesn't need anything from the object. You also never made the unique_ptr actually point to anything.
Instead, make the unique_ptr point to something. After it's moved, try calling a virtual function or accessing a member whose value is changed by the destructor. Like this:
#include <iostream>
#include <memory>
class T{
public:
T() : valid (true) {}
~T() { valid = false; }
bool valid;
void show(){
std::cout << "HEJ! " << valid << std::endl;
}
};
void f(std::unique_ptr<T> ref){
ref->show();
}
int main()
{
std::unique_ptr<T> my (new T); // Make it point to a new object
my->show();
f(std::move(my));
my->show(); // Try to access
return 0;
}
in the line f(std::unique_ptr<T>&& uptr) uptr is not an object - it's a reference. a reference which capable to catch temporeries and mutate them.
it's like asking why doesn't the object get cloned in the next example
void func(std::string& str);
std::string str_ = "yyy";
func(str_);
str_ is passed by "regular" reference and won't get copied - this is what pass by reference means.
std::move only cast l-value to r-value-reference, which uptr in f(std::unique_ptr<T>&& uptr) can reference, it's a reference referencing an object. opposed to the common conception, std::move won't do any moving by itself, only casts the object to r-value-reference for the move constructor/assg. operator to kick in.
here, the pointer still holds valid data since it was not moved, only casted to r-value-reference.
if you want the object to move you have to declare the parameter as object, not reference : f(std::unique_ptr<T> uptr)
In your edit, you have undefiend behaviour, so everything may occure.
The reason why your call to show doesn't crash is because it doesn't use the this pointer (it doesn't try to modify or access a data member).
Try this:
class T{
public:
int v;
T(){}
void show(){
v = 0;
std::cout << "HEJ!\n";
}
};
void f(std::unique_ptr&& ref)
This is the answer when you initially had your f function taking a rvalue reference &&.
Your function takes a rvalue reference. Therefore, no new unique_ptr object is created yet, you are simply passing a reference.
Inside your f function, if you create a a local unique_ptr, with the parameter uptr, then finally uptr will be moved to create that new object.
template<typename T>
void f(std::unique_ptr<T>&& uptr)
{
//move uptr into local_unique_ptr
//note that we have to use move again
//because uptr has a name, therefore its a lvalue.
auto local_unique_ptr = std::unique_ptr<T>(std::move(uptr));
}
The important thing to always know is that std::move is simply a static_cast.
If you pass a lvalue to std::move, it returns a rvalue. If you pass a rvalue, it returns a rvalue. That's it.
Your function f may not in fact move the pointer. Merely taking an object by && does not modify the object.
u_ptr->do_sth() may invoke a static member function or a member function that does not access the object (this) and this is why it does not crash.
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.
When a function returns a value, this is put on the stack (the function stack frames are deleted, but the return value remains there until the caller gets it).
If the return value is on the stack how can the move get that value without copying it in the variable memory location?
For example in this code:
A a = getA();
In many implementations of C++, a function returning a "complex" data type is passed a hidden parameter that is a pointer to the space where the returned instance is to reside. Essentially, the compiler turns Foo r = fun(); into
char alignas(Foo) r[sizeof Foo]; // Foo-sized buffer, unitialized!
fun(&r);
As you can see, Foo is allocated on the stack in the caller's frame. Now, within the implementation of fun there could be a copy. The construction
Foo fun() {
Foo rv;
...
return rv;
}
is generally implemented as
void fun(Foo * $ret) {
Foo rv;
..
new ($ret) Foo(rv); // copy construction
}
When the return value optimizations are applied, this gets changed to
void fun(Foo * $ret) {
Foo & rv = *(new ($ret) Foo);
...
return;
}
Now there's no copying involved. That's a mile-high overview of how an implementation might do it.
The storage (Heap, stack, registers, etc) used to store the temporary used to return values from a function is implementation defined. You could see it as:
+-----------------------------+-------------------------+-----------------------------------------+
| target (caller stack frame) | temporary (unspecified) | return statement (function stack frame) |
+-----------------------------+-------------------------+-----------------------------------------+
The value is passed from the right to the left. Also note that the standard specifies that any compiler could elide the temporary and the assigments/copies/moves and directly initialize the target.
Writting a class such as:
class trace
{
public:
trace()
{
std::cout << "Init" << std::endl;
}
~trace()
{
std::cout << "Destroy" << std::endl;
}
trace( const trace& )
{
std::cout << "Copy init" << std::endl;
}
trace( trace&& )
{
std::cout << "Move init" << std::endl;
}
trace& operator=( const trace& )
{
std::cout << "Copy assign" << std::endl;
}
trace& operator=( trace&& )
{
std::cout << "Move assign" << std::endl;
}
};
And trying it with different compiler optimizations enabled is very ilustrative.
You're assuming that A is an aggregate or primitive. If this is true then yes move and copy semantics are equivalent. If however A is a complex type like vector then it will contain pointers to resources. When moving the object the pointers are copied without copying the value they point to.
When you say "move", I assuming you're referring to C++11 move constructors and the std::move function.
Moving an object doesn't actually move the entire object. It constructs a new one using its move constructor, which is allowed to take ownership of resources held by the original object instead of copying them. For example, if you write:
std::vector<int> foo = function_that_returns_a_vector();
the compiler may implement this by calling foo's move constructor and passing it the temporary vector returned by the function. The move constructor will take ownership of the temporary vector's internal pointer to its heap-allocated contents, leaving the temporary vector empty. Prior to C++11 and move support, foo's copy constructor would've been called, which would've allocated new space on the heap to copy the returned vector's contents even though that returned vector is about to be destroyed and won't need its own copy any longer.
Note that the compiler won't necessarily implement that line by constructing foo from a returned temporary at all, though. Depending on the compiler's platform-specific calling convention, the address of the (uninitialized) foo variable may be passed into the function in such a way that the function's return value is constructed directly into foo, avoiding the need for a copy after the function returns. This is called copy elision.
The easiest is to modify your method like this:
void getA(A& out);
A a;
getA(a);
However, your compiler does it's best to avoid such superfluity: Copy Elision
here is my c++ code :
class Sample
{
public:
int *ptr;
Sample(int i)
{
ptr = new int(i);
}
~Sample()
{
delete ptr;
}
void PrintVal()
{
cout << "The value is " << *ptr;
}
};
void SomeFunc(Sample x)
{
cout << "Say i am in someFunc " << endl;
}
int main()
{
Sample s1= 10;
SomeFunc(s1);
s1.PrintVal();
}
it returns me the output like :
Say i am in someFunc
Null pointer assignment(Run-time error)
here As the object is passed by value to SomeFunc the destructor of the object is called when the control returns from the function
should i right ? if yes then why it is happening ? and whats the solution for this ???
Sample is passed by value to SomeFunc, which means a copy is made. The copy has the same ptr, so when that copy is destroyed when SomeFunc returns, ptr is deleted for both objects. Then when you call PrintVal() in main you dereference this invalid pointer. This is undefined behavior. Even if that works then when s1 is destroyed ptr is deleted again, which is also UB.
Also, if the compiler fails to elide the copy in Sample s1= 10; then s1 won't even be valid to begin with, because when the temporary is destroyed the pointer will be deleted. Most compilers do avoid this copy though.
You need to either implement copying correctly or disallow copying. The default copy-ctor is not correct for this type. I would recommend either making this type a value type (which holds its members directly rather than by pointer) so that the default copy-ctor works, or use a smart pointer to hold the reference so that it can manage the by-reference resources for you and the default copy-ctor will still work.
One of the things I really like about C++ is that it's really friendly toward using value types everywhere, and if you need a reference type you can just wrap any value type up in a smart pointer. I think this is much nicer than other languages that have primitive types with value semantics but then user defined types have reference semantics by default.
You usually need to obey the Rule of Three since you have an pointer member.
In your code example to avoid the Undefined Behavior you are seeing:
Replace the need to in first statement by must.
Since SomeFunc() takes its argument by value, the Sample object that you pass to it is copied. When SomeFunc() returns, the temporary copy is destroyed.
Since Sample has no copy constructor defined, its compiler-generated copy constructor simply copies the pointer value, so both Sample instances point to the same int. When one Sample (the temporary copy) is destroyed, that int is deleted, and then when the second Sample (the original) is destroyed, it tries to delete the same int again. That's why your program crashes.
You can change SomeFunc() to take a reference instead, avoiding the temporary copy:
void someFunc(Sample const &x)
and/or you can define a copy constructor for Sample which allocates a new int rather than just copying the pointer to the existing one.
When you pass the argument for the function it's called the copy constructor, but you don't have one so the pointer is not initialised. When it exits the function, the object is calls the destructor to delete the unitialised pointer, so it thows an error.
Instead of
int main()
{
Sample s1= 10;
SomeFunc(s1);
s1.PrintVal();
}
try to use
int main()
{
Sample* s1= new Sample(10);
SomeFunc(*s1);
s1->PrintVal();
}
boost::shared_ptr has an unusual constructor
template<class Y> shared_ptr(shared_ptr<Y> const & r, T * p);
and I am a little puzzled as to what this would be useful for. Basically it shares ownership with r, but .get() will return p. not r.get()!
This means you can do something like this:
int main() {
boost::shared_ptr<int> x(new int);
boost::shared_ptr<int> y(x, new int);
std::cout << x.get() << std::endl;
std::cout << y.get() << std::endl;
std::cout << x.use_count() << std::endl;
std::cout << y.use_count() << std::endl;
}
And you will get this:
0x8c66008
0x8c66030
2
2
Note that the pointers are separate, but they both claim to have a use_count of 2 (since they share ownership of the same object).
So, the int owned by x will exist as long as x or y is around. And if I understand the docs correct, the second int never gets destructed. I've confirmed this with the following test program:
struct T {
T() { std::cout << "T()" << std::endl; }
~T() { std::cout << "~T()" << std::endl; }
};
int main() {
boost::shared_ptr<T> x(new T);
boost::shared_ptr<T> y(x, new T);
std::cout << x.get() << std::endl;
std::cout << y.get() << std::endl;
std::cout << x.use_count() << std::endl;
std::cout << y.use_count() << std::endl;
}
This outputs (as expected):
T()
T()
0x96c2008
0x96c2030
2
2
~T()
So... what is the usefulness of this unusual construct which shares ownership of one pointer, but acts like another pointer (which it does not own) when used.
It is useful when you want to share a class member and an instance of the class is already a shared_ptr, like the following:
struct A
{
int *B; // managed inside A
};
shared_ptr<A> a( new A );
shared_ptr<int> b( a, a->B );
they share the use count and stuff. It is optimization for memory usage.
To expand on leiz's and piotr's answers, this description of shared_ptr<> 'aliasing' is from a WG21 paper, "Improving shared_ptr for C++0x, Revision 2":
III. Aliasing Support
Advanced users often require the
ability to create a shared_ptr
instance p that shares ownership with
another (master) shared_ptr q but
points to an object that is not a base
of *q. *p may be a member or an
element of *q, for example. This
section proposes an additional
constructor that can be used for this
purpose.
An interesting side effect of this
increase of expressive power is that
now the *_pointer_cast functions can
be implemented in user code. The
make_shared factory function presented
later in this document can also be
implemented using only the public
interface of shared_ptr via the
aliasing constructor.
Impact:
This feature extends the interface of
shared_ptr in a backward-compatible
way that increases its expressive
power and is therefore strongly
recommended to be added to the C++0x
standard. It introduces no source- and
binary compatibility issues.
Proposed text:
Add to shared_ptr
[util.smartptr.shared] the following
constructor:
template<class Y> shared_ptr( shared_ptr<Y> const & r, T * p );
Add the following to
[util.smartptr.shared.const]:
template<class Y> shared_ptr( shared_ptr<Y> const & r, T * p );
Effects: Constructs a shared_ptr instance that stores p and shares ownership with r.
Postconditions: get() == p && use_count() == r.use_count().
Throws: nothing.
[Note: To avoid the possibility of a dangling pointer, the user
of this constructor must ensure that p remains valid at least
until the ownership group of r is destroyed. --end note.]
[Note: This constructor allows creation of an empty shared_ptr
instance with a non-NULL stored pointer. --end note.]
You can also use this to keep dynamic casted pointers, i.e.:
class A {};
class B: public A {};
shared_ptr<A> a(new B);
shared_ptr<B> b(a, dynamic_cast<B*>(a.get()));
You might have a pointer to some driver or a lower level api's data structure that may allocate additional data by its lower level api or other means. In this case it might be interesting to increase the use_count but return the additional data if the first pointer owns the other data pointers.
I have put shared_ptr's aliasing constructor in use in my little library:
http://code.google.com/p/infectorpp/ (just my simple IoC container)
The point is that since I needed a shared_ptr of known type to be returned from a polymorphic class (that does not know the type). I was not able to implicitly convert the shared_ptr to the type I needed.
In the file "InfectorHelpers.hpp" (line 72-99) you can see that in action for the type IAnyShared.
Aliasing constructor creates shared_ptr that does not delete the pointers they are actually pointing to, but they still increase the reference counter to the original object and that can be tremendously usefull.
Basically you can create a pointer to anything using aliasing constructor and threat it as a reference counter.
//my class
std::shared_ptr<T> ist;
int a; //dummy variable. I need its adress
virtual std::shared_ptr<int> getReferenceCounter(){
return std::shared_ptr<int>(ist,&a); //not intended for dereferencing
}
virtual void* getPtr(); //return raw pointer to T
now we have both "a reference counter" and a pointer to a istance of T, enough data to create something with the aliasing constructor
std::shared_ptr<T> aPtr( any->getReferenceCounter(), //share same ref counter
static_cast<T*>(any->getPtr()) ); //potentially unsafe cast!
I don't pretend to have invented this use for the aliasing constructor, but I never seen someone else doing the same. If you are guessing if that dirty code works the answer is yes.
For "shared_ptr<B> b(a, dynamic_cast<B*>(a.get()));"
I think it is not the recommended way using smart pointer.
The recommended way of doing this type conversion should be:
shared_ptr<B> b(a);
Since in Boost document it is mentioned that:
shared_ptr<T> can be implicitly
converted to shared_ptr<U> whenever T*
can be implicitly converted to U*. In
particular, shared_ptr<T> is
implicitly convertible to shared_ptr<T> const,
to shared_ptr<U> where U is an
accessible base of T, and to
shared_ptr<void>.
In addition to that, we also have dynamic_pointer_cast
which could directly do conversion on Smart Pointer object and both of these two methods would be much safer than the manually casting raw pointer way.