Suppose that we have
void UsePointer (auto_ptr <CSomeClass> spObj)
{
spObj->DoSomething();
}
and we have a main function:
int main()
{
auto_ptr <CSomeClass> spObject (new CSomeClass ());
UsePointer (spObject);
// spObject->DoSomthing (); would be invalid.
}
The book says "the object was destroyed when UsePointer() returned, because variable spObj went out of scope, hence destroyed"
My question is:
Is the pointer copied when passed into UsePointer function? Hence the owernship is transferred?
What do I need to if want spObject not be destroyed? Do I need to pass this pointer by reference?
Also this book is a bit outdated - does the same hold for unique_ptr in c++ 11?
Is the pointer copied when passed into UsePointer function? Hence the owernship is transferred?
Yes. Unless the function parameter is reference qualified, arguments pass by value. For auto_ptr that involves copying, and thus passing ownership.
What do I need to if want spObject not be destroyed? Do I need to pass this pointer by reference?
You could. But better yet, pass a reference to the object itself. A function shouldn't accept smart pointers unless manipulation of the ownership is involved. If it just needs to do something with pointee, accept a CSomeClass const& and pass *spObject.
Also this book is a bit outdated - does the same hold for unique_ptr in c++ 11?
Yes. With the difference that unique_ptr is not copyable, and so cannot pass its ownership away implicitly. To pass a unique_ptr, it must be moved explicitly. The appearance of std:move in the code that passes the pointer into the function gives an explicit visual cue that ownership changes.
Related
I'd like to optimize my code. I have one class that has a shared_ptr data member. In some methods of this class, I create objects that need to use this member (just to get information from the object pointed by shared_ptr). I know that lifetime of these created objects is lower than in my main class.
How to pass this pointer? I think another shared_ptrs is unnecessary (because I have a warranty that the object will exist). So what should get my created classes? Should they get raw pointer? Weak_ptr? Or the best solution is getting shared_ptr (and incrementing its reference counter)? What is the most standard solution?
In this case when you know the life-time of your shared resource will outlive those that you pass the pointer to the correct thing to do is pass a reference or a raw pointer:
void func(object* o)
{
// do stuff with o
}
// ...
std::shared_ptr<object> sp;
// ...
func(sp.get()); // pass raw pointer
The main reason for this is that the function can be useful no matter what kind of smart pointer is managing the resource. By accepting the raw pointer your function is able to accept objects from shared pointers as well as unique pointers and any other third party smart pointer.
There is no benefit to passing in the smart pointer unless the function needs to modify the smart pointer itself.
A good set of guidelines being produced by Bjarne Straustrup & Herb Sutter can be found here: CppCoreGuidelines
The rule about passing raw pointers (or references):
F.7
Passing a smart pointer transfers or shares ownership and should only be used when ownership semantics are intended. A function that does not manipulate lifetime should take raw pointers or references instead.
Passing by smart pointer restricts the use of a function to callers that use smart pointers. A function that needs a widget should be able to accept any widget object, not just ones whose lifetimes are managed by a particular kind of smart pointer.
When passing the shared_ptr into a function that will not store the resource, pass it by reference:
void foo(const shared_ptr<T>& ptr)
{
// Basically just a pointer dereference
std::cout << ptr->bar() << '\n';
}
int main()
{
std::shared_ptr<T> ptr{std::make_shared<T>()};
foo(ptr);
}
That won't increment the reference count, but that's fine — you're effectively treating it as a raw pointer (because you're just temporarily inspecting the pointee) but in a way that's safe because if you accidentally copy it then you'll get the reference count increment that can save your life. :)
However, if foo needs to store any sort of handle to this object, then you should pass in the shared_ptr by copy … or consider using weak_ptr so that you at least get some semblance of safety.
The above contrived example is so simple that I'd actually make it the following:
void foo(const T& ptr)
{
std::cout << ptr.bar() << '\n';
}
int main()
{
std::shared_ptr<T> ptr{std::make_shared<T>()};
foo(*ptr.get());
}
This question already has answers here:
What is a reference variable in C++?
(12 answers)
Closed 8 years ago.
Facts that I have known:
There are three types of variables in C++: variables, pointers and references.
Variables is kinda label for the memory that stores the actual data.
Pointers stored the address of the variables.
References are alias for the variables.
My questions:
By observation, the use of variables names and references is exchangeable. Is that true?
What is the difference between passing a variable name as parameter and passing a reference? e.g.,
void func(int a); vs void func2(int& b);
Thanks a million!
Here is a way to understand the difference:
Objects that can change state are also called "variables".
Pointers are objects (variable or not). They have a state.
References are "nicknames". They don't have a state, but expose the state of the refereed object (which is why you can't re-assign a reference, it's not an actual object).
Now, in some cases references might be implemented as pointers, but from the language point of view, references are just not pointers, they really are additional names for an object already existing.
As pointers are objects, and have a state, passing pointers to functions will copy that state, the pointer's state, not the pointee's state. However, references have no state, so if you pass a reference to a function, it's the refereed object that you pass (by copy).
By observation, the use of variables names and references is
exchangeable. Is that true?
"References are nickname" is the best way to understand references.
What is the difference between passing a variable name as parameter
and passing a reference? e.g.,
void func(int a); vs void func2(int& b);
The first implementation ask for a copy of the object passed. That is, internally func() can do anything to a, without changing the object that was passed to func() because internally func() made a copy of that object and manipulates the copy, not the original.
The second implementation ask for "a nickname for an object already existing". First, the object have to exist and if passed, a nickname for it will be created inside the function. That nickname, the reference b, is still a nickname for the original object. This mean that any manipulation done to b will affect the original object passed to func2().
func() signature says "I need this data but I will not modify the original object passed.".
func2() signature says "I need an object that I WILL certainly modify, pass it so that I can modify it".
Bonus stage:
At this point, if you don't know yet about const, that might be useful: in function signatures const is used with references to specify the arguments that are "read-only".
Let me clarify:
void func3( const int& b);
Here func3 says: "I need to access to an object, but really I will not make a copy of it. However I guarantee that I will not change that object".
So, why would we need that? Because some objects are expensive to copy. int is cheap to copy so most people will just pass it and func() and func3() are basically equivalent (depends on implementation but generally true).
If however we want to pass, says, a very big object, like a data buffer, we really don't want to copy it again and again just to apply some algorithms.
So we do want to pass it by reference. However, depending on the function, sometime you want to extract information and work with it, so you only need "read-only" access to the argument. In this case you use const Object&. However, if you need to apply the algorithm to the object passed, you need to be able to modify it, which you could call "write-access". In this case, you need to use a normal reference.
Asking for a copy basically mean that you want to manipulate an object that is the same state than the passed object, but is not the passed object.
To summarize:
func( T object ) : I want to have a copy of an object of type T;
func( T& object ) : I want to have "write-access" to an object of type T - assume that I will modify that object!;
func( const T& object ) or func( T const & object ) // which are the same : I want to read the state of an object, but I guarantee you that I will not modify it, I want "read-only" access.
Actually, the "read-only" guarantee could be violated using const_cast<> but that's a different story and it's only used in some very very very narrow cases.
Last thing you need to know is that if you have a member function, then you can do:
class K{
public:
void func() const; // see the const?
};
In this specific case, what you say is that inside the function, which is basically equivalent to:
void func( const K* this );
In this case you can see that this is a pointer but it's pointing to a const object. This mean that func() guarantee that the object it is member of (this) is never modified through this function (except some specific cases, see mutable keyword, another long story).
Let's say you have these two functions:
void addone(int a) {
a += 1;
}
void addone_bis(int &a) {
a += 1;
}
If you call the first function in your main function, the value will only change in the function addone and not in the main, whereas if you call addone_bis the value of a will also be changed in the main function.
int main() {
int test_a = 10;
int test_b = 11;
addone(test_a);
// test_a still equals 10.
addone_bis(test_b);
// test_b now equals 12.
}
Did I correctly answer to your question?
Your first example is what is known as PASSING BY VALUE. What this means is that a copy of the ACTUAL value is passed into the routine.
When passing in the way of your second example, this is what is known as PASSING BY REFERENCE. A reference is ESSENTIALLY a passing of the variable into the routine such that its ACTUAL VALUE can be modified by the called routine without DE-REFERENCING.
I want to ask about passing pointers between functions or between objects or returning them .. I heard that passing or returning pointers in general (whether they point to an array or an object or whatever they are pointing at) isn't safe and the output isn't guaranteed.
now I've tried it and so far everything seems OK but I don't want my project to work by accident .. so can someone explain to me why not to pass or return pointers and what are the suggested solution (for example, what if I want to modify the same object (say object1) in a function in another object (function func in object2))?
also, I read in a tutorial that everything in c++ is pass by value? isn't passing pointers is called pass by reference?
Thanx everybody.
I want to ask about passing pointers between functions or between objects or returning them .. I heard that passing or returning pointers in general (whether they point to an array or an object or whatever they are pointing at) isn't safe and the output isn't guaranteed.
Where did you get that from? In general, it's not true and of course you can pass around pointers.
The tricky thing is managing ownership of (heap-allocated) objects, since somewhere you have to release the memory again. In other words: When you allocate memory with new, you will have to free it again with delete.
Example:
A* function1(A* a) {
return a;
}
B* function2(B* b) {
return new B(b);
}
function1 returns an existing pointer. Whoever owned the A object passed in will also own the returned one, as it is the same. This needs to be documented since this knowledge is essential for using function1!
function2 creates a new object of class B by coping its input argument. Whoever calls function2 will own the returned object and will be responsible to delete it when it's done. Again, this needs to be documented!
also, I read in a tutorial that everything in c++ is pass by value? isn't passing pointers is called pass by reference?
Technically, passing pointers is pass-by-value since the pointer itself gets copied. But since a pointer is a "reference type", you essentially get pass-by-reference with that.
Note that C++ also knows references (int&), which really is pass-by-reference.
Well, the honest answer is that people sometimes mean different things when they say "pass by reference".
But generally, when people say "pass by reference", they mean this:
void readInt(int &a) {
cin >> a;
}
int a;
readInt(a);
cout << a;
And "pass by pointer" would be this:
void readInt(int *a) {
cin >> *a;
}
int a;
readInt(&a);
cout << a;
Ultimately, you can use pointers for everything that references are used for (they other way around is mostly true).
Some people like references because they can use the . operator, like they normally do. Others prefer pointers because they are explicit.
Note that pointers are older than references (C does not have references), so C libraries will use pointers exclusively.
Most people (I think) use references when they can (like in your hypothetical example). The nice thing is that type safety will stop you if you confuse references and pointers.
Been stuck on this code for the past hour, still trying to get my head around smart pointers and implementing them but this issue has had my stumped for quite a bit.
void GameState::addEntity(std::unique_ptr<Entity> gameObject)
{
if(gameObject->isCollidable()){
_actors.Add(gameObject);
} else {
_props.Add(gameObject);
}
}
// This is the method the above function is trying to call.
void GameObjectManager::Add(std::unique_ptr<Entity> gameObject)
{
_gameObjects.insert(std::make_pair(ID, std::move(gameObject)));
ID++;
}
The error message I'm reciving is;
'std::unique_ptr<_Ty>::unique_ptr' : cannot access private member declared in class 'std::unique_ptr<_Ty>'
You need to pass ownership from addEntity to Add by using std::move:
if(gameObject->isCollidable()){
_actors.Add(std::move(gameObject));
} else {
_props.Add(std::move(gameObject));
}
You cannot pass a unique_ptr without explicitly allowing it to be moved from. This is what makes it a unique pointer. If you could copy it, both the original and the copy would be pointing to the same object. When you move from it, the original pointer gives up ownership to the new one.
You cannot pass a unique_ptr by value. Following are trying to create copies of a unique_ptr, which is forbidden:
if(gameObject->isCollidable()){
_actors.Add(gameObject); // THIS LINE
} else {
_props.Add(gameObject); // and THIS LINE
}
A solution is passing with std::move():
if(gameObject->isCollidable()){
_actors.Add(std::move(gameObject));
// ^^^^^^^^^
} else {
_props.Add(std::move(gameObject));
// ^^^^^^^^^
}
This will result in two ownership transfers. One to the std::unique_ptr<Entity> which is the input parameter of GameObjectManager::Add and one to the std::pair in _gameObjects.
Another solution is modifying the signature of GameObjectManager::Add to get a reference:
void GameObjectManager::Add(std::unique_ptr<Entity> & gameObject)
// ^^^
Now, you can call the method as you are currently doing, and this will result in only a single ownership transfer (to the pair in _gameObjects).
But, as pointed out by #Xeo in the comments the second option violates the best practice rule-of-thumb which is: Ownership transfer should be explicit at all points.
You are trying to pass a unique_ptr lvalue to a function which takes a unique_ptr by value, which would result in creating a copy of that pointer: this is intentionally forbidden. Unique pointers are meant to model unique ownership: this means that the entity that holds a unique pointer has the ownership of the pointed object.
Copying a unique pointer around would mean having several owning pointers spread all over the system: this would of course defeat the purpose itself of unique ownership, which explains why you can't copy unique pointers.
What you can do is to transfer this ownership, so if you call a function that accepts a unique pointer, you could move the unique_ptr when you pass it as an argument to that function:
_actors.Add(std::move(gameObject));
// ^^^^^^^^^
Notice, that transferring ownership by moving away from a unique pointer means that the caller function is left with a "zombie" unique pointer object which is no longer owning the object it previously pointed to: therefore, the caller function should not try to dereference it anymore.
I wrote a function along the lines of this:
void myFunc(myStruct *&out) {
out = new myStruct;
out->field1 = 1;
out->field2 = 2;
}
Now in a calling function, I might write something like this:
myStruct *data;
myFunc(data);
which will fill all the fields in data. If I omit the '&' in the declaration, this will not work. (Or rather, it will work only locally in the function but won't change anything in the caller)
Could someone explain to me what this '*&' actually does? It looks weird and I just can't make much sense of it.
The & symbol in a C++ variable declaration means it's a reference.
It happens to be a reference to a pointer, which explains the semantics you're seeing; the called function can change the pointer in the calling context, since it has a reference to it.
So, to reiterate, the "operative symbol" here is not *&, that combination in itself doesn't mean a whole lot. The * is part of the type myStruct *, i.e. "pointer to myStruct", and the & makes it a reference, so you'd read it as "out is a reference to a pointer to myStruct".
The original programmer could have helped, in my opinion, by writing it as:
void myFunc(myStruct * &out)
or even (not my personal style, but of course still valid):
void myFunc(myStruct* &out)
Of course, there are many other opinions about style. :)
In C and C++, & means call by reference; you allow the function to change the variable.
In this case your variable is a pointer to myStruct type. In this case the function allocates a new memory block and assigns this to your pointer 'data'.
In the past (say K&R) this had to be done by passing a pointer, in this case a pointer-to-pointer or **. The reference operator allows for more readable code, and stronger type checking.
It may be worthwhile to explain why it's not &*, but the other way around. The reason is, the declarations are built recursively, and so a reference to a pointer builds up like
& out // reference to ...
* (& out) // reference to pointer
The parentheses are dropped since they are redundant, but they may help you see the pattern. (To see why they are redundant, imagine how the thing looks in expressions, and you will notice that first the address is taken, and then dereferenced - that's the order we want and that the parentheses won't change). If you change the order, you would get
* out // pointer to ...
& (* out) // pointer to reference
Pointer to reference isn't legal. That's why the order is *&, which means "reference to pointer".
This looks like you are re-implementing a constructor!
Why not just create the appropriate constructor?
Note in C++ a struct is just like a class (it can have a constructor).
struct myStruct
{
myStruct()
:field1(1)
,field2(2)
{}
};
myStruct* data1 = new myStruct;
// or Preferably use a smart pointer
std::auto_ptr<myStruct> data2(new myStruct);
// or a normal object
myStruct data3;
In C++ it's a reference to a pointer, sort of equivalent to a pointer to pointer in C, so the argument of the function is assignable.
Like others have said, the & means you're taking a reference to the actual variable into the function as opposed to a copy of it. This means any modifications made to the variable in the function affect the original variable. This can get especially confusing when you're passing a pointer, which is already a reference to something else. In the case that your function signature looked like this
void myFunc(myStruct *out);
What would happen is that your function would be passed a copy of the pointer to work with. That means the pointer would point at the same thing, but would be a different variable. Here, any modifications made to *out (ie what out points at) would be permanent, but changes made to out (the pointer itself) would only apply inside of myFunc. With the signature like this
void myFunc(myStruct *&out);
You're declaring that the function will take a reference to the original pointer. Now any changes made to the pointer variable out will affect the original pointer that was passed in.
That being said, the line
out = new myStruct;
is modifying the pointer variable out and not *out. Whatever out used to point at is still alive and well, but now a new instance of myStruct has been created on the heap, and out has been modified to point at it.
As with most data types in C++, you can read it right-to-left and it'll make sense.
myStruct *&out
out is a reference (&) to a pointer (*) to a myStruct object. It must be a reference because you want to change what out points at (in this case, a new myStruct).
MyClass *&MyObject
Here MyObject is reference to a pointer of MyClass. So calling myFunction(MyClass *&MyObject) is call by reference, we can change MyObject which is reference to a pointer. But If we do myFunction( MyClass *MyObject) we can't change MyObject because it is call by value, It will just copy address into a temporary variable so we can change value where MyObject is Pointing but not of MyObject.
so in this case writer is first assigning a new value to out thats why call by reference is necessary.