i just wanted to know what is the best way to pass a local variable to a function.
void check2 (int* var2){
*var2=7;
}
void check1 (int& var){
var=6;
}
int main()
{
int var;
int* var2=new int;
check1(var);
check2(var2);
delete var2;
return 0;
}
In check1, I pass the variable using a reference. As I am passing a local variable to the function check1, wouldn't it get out of scope once main terminates and there would be no variable anymore?
I found a couple of examples where the operator new is used to allocate memory and return a pointer which is then passed to the function. Is this a better way to do the same task as the variable doesn't get erased?
[What is the] Best way to pass local variable to function
Depends on why you pass the variable, and what you do with it.
Passing a reference implies that the function does not take ownership of the object, and the function clearly doesn't take ownership, so that's appropriate. Passing a bare pointer is ambiguous about change of ownership so in this case, reference is better.
As I am passing a local variable to the function check1, wouldn't it get out of scope once main terminates and there would be no variable anymore?
Correct. However, whether the object exists after main returns, is mostly orthogonal to the question of how to pass the object to a function within main.
Also do realize that after main returns, the whole program is about to terminate. The only situation where you'd still need an object to exist at that point, is if that object is depended on by a destructor of another object that has static storage.
I found a couple of examples where the operator new is used to allocate memory and return a pointer which is then passed to the function. Is this a better way to do the same task as the variable doesn't get erased?
If you do need to create an object in main, but need that object to exist after main has finished, then dynamic allocation is one way to achieve that. Static storage might be an alternative.
In this example however, you delete the object in main, so it gets destroyed just like the local variable does, so in this case, the dynamic allocation offers no advantage.
Related
Consider the below example where I create the local variable specialNumber in main(), and pass it by reference to a new thread, as well as another function (please disregard the lack of a lock/mutex):
#include <iostream>
#include <thread>
void threadRun(int& number) {
while(true) {
std::this_thread::sleep_for(std::chrono::seconds(2));
std::cout << number << std::endl;
number += 1;
}
}
int main() {
int specialNumber = 5;
std::thread newThread(threadRun, std::ref(specialNumber));
otherFunction(specialNumber);
newThread.join();
}
void otherFunction(int& number) {
// does something with number
}
I am aware that passing references to local variables around should generally be avoided, as once that function terminates the variable will be out of scope and the reference will be invalid.
However, since the variable is local to main(), and that function won't terminate until the whole program terminates, is there anything wrong with this practice?
My specific use-case would be storing a small object here (mainly consisting of pointers to heap objects along with helper functions), which would be used by multiple threads and/or functions, and passing around a reference to it. I'm aware an alternative is storing it in the heap with a smart pointer such as shared_ptr, but storing such a small object this way seems inefficient to me.
I apologize if any of my terminology is incorrect, I am quite new to C++. Please do correct me!
Your assumption
I am aware that passing references to local variables around should generally be avoided
seems unfounded.
There is nothing wrong with passing references to functions. However, a function that takes a reference to an object should not take ownership of that object. The function should not assume that the referenced object continues to live after it exits.
This is different from returning references to local variables, which is always wrong.
I see no problem (missing synchronization aside) with passing references to threads and this generally preferable to the alternative of using global variables.
Smart pointers, such as std::shared_ptr, are only required if the functions are supposed to take (shared) ownership of the object, e.g. if threadRun wants to keep a reference/pointer to the object after it exits.
As long as the main thread is living you shouldn't see a problem occurring since the lifetime of specialNumber is controlled by it.
However I want to elaborate on the use of std::ref(). One of the uses of std::ref() is precisely the scenario you are coding.
When you use std::ref() you are actually returning a std::reference_wrapper which can be copied. Reference wrappers can be stored in containers whereas plain references cannot.
Passing objects by reference to the constructor of a thread is one of the ways in which a reference wrapper comes in useful and std::ref() returns a reference wrapper.
Had you passed a simple reference you would see different behavior.
Read more about std::ref() and std::reference_wrapper
This thread How is tr1::reference_wrapper useful? is also helpful.
I made the following method in a C++/CLI project:
void GetSessionData(CDROM_TOC_SESSION_DATA& data)
{
auto state = CDROM_TOC_SESSION_DATA{};
// ...
data = state;
}
Then I use it like this in another method:
CDROM_TOC_SESSION_DATA data;
GetSessionData(data);
// do something with data
It does work, returned data is not garbage, however there's something I don't understand.
Question:
C++ is supposed to clean up state when it has exitted its scope, so data is a copy of state, correct ?
And in what exactly it is different from the following you see on many examples:
CDROM_TOC_SESSION_DATA data;
GetSessionData(&data); // signature should be GetSession(CDROM_TOC_SESSION_DATA *data)
Which one makes more sense to use or is the right way ?
Reference:
CDROM_TOC_SESSION_DATA
Using a reference vs a pointer for an out parameter is really more of a matter of style. Both function equally well, but some people feel that the explicit & when calling a function makes it more clear that the function may modify the parameter it was passed.
i.e.
doAThing(someObject);
// It's not clear that doAThing accepts a reference and
// therefore may modify someObject
vs
doAThing(&someObject);
// It's clear that doAThing accepts a pointer and it's
// therefore possible for it to modify someOjbect
Note that 99% of the time the correct way to return a class/struct type is to just return it. i.e.:
MyType getObject()
{
MyType object{};
// ...
return object;
}
Called as
auto obj = getObject();
In the specific case of CDROM_TOC_SESSION_DATA it likely makes sense to use an out parameter, since the class contains a flexible array member. That means that the parameter is almost certainly a reference/pointer to the beginning of some memory buffer that's larger than sizeof(CDROM_TOC_SESSION_DATA), and so must be handled in a somewhat peculiar way.
C++ is supposed to clean up state when it has exitted its scope, so
data is a copy of state, correct ?
In the first example, the statement
data = state
presumably copies the value of state into local variable data, which is a reference to the same object that is identified by data in the caller's scope (because those are the chosen names -- they don't have to match). I say "presumably" because in principle, an overridden assignment operator could do something else entirely. In any library you would actually want to use, you can assume that the assignment operator does something sensible, but it may be important to know the details, so you should check.
The lifetimes of local variables data and state end when the method exits. They will be cleaned up at that point, and no attempt may be made to access them thereafter. None of that affects the caller's data object.
And in what exactly it is different from the following you see on many
examples:
CDROM_TOC_SESSION_DATA data;
GetSessionData(&data);
Not much. Here the caller passes a pointer instead of a reference. GetSessionData must be declared appropriately for that, and its implementation must explicitly dereference the pointer to access the caller's data object, but the general idea is the same for most intents and purposes. Pointer and reference are similar mechanisms for indirect access.
Which one makes more sense to use or is the right way ?
It depends. Passing a reference is generally a bit more idiomatic in C++, and it has the advantage that the method does not have to worry about receiving a null or invalid pointer. On the other hand, passing a pointer is necessary if the function has C linkage, or if you need to accommodate the possibility of receiving a null pointer.
I have a simple question that I am not 100% sure on.
Let us say I have a Entity class, that handles objects on the screen. Let us say the Entity class has two float variables, 'x' and 'y' (aka coordinates). Also let us say the entity I am passing has already been declared and is in memory.
I have another class that handles camera movement. It requires an entity to center on. The entity that it is centered on can changed, so I need to use a pointer here I believe. The only thing I do here is grab the X and Y variables when needed. Nothing is changed here.
I've defined it as
void StarField::ChangeFollowEntity(Entity* newFollowEntity) {
followEntity = newFollowEntity;
}
where followEntity is also an Entity class. I would call ChangeFollowEntity(..) to change the entity. Is this actually correct?
I've also seen however this:
void StarField::ChangeFollowEntity(Entity newFollowEntity) {
followEntity = &newFollowEntity;
}
In both cases followEntity is defined as Entity* followEntity; .. What does the second example exactly do here? From what I understand, & would typically be used as a reference type. Maybe it is incorrect to do to begin with.
I am pretty sure I shouldn't be using a reference in this case because the followEntity changes, which references I believe cannot change and must be defined.
So my question is, is my first example correct and the right way to do it? What does the second example do exactly?
In your second version ::
void StarField::ChangeFollowEntity(Entity newFollowEntity) {
followEntity = &newFollowEntity;
}
You pass the newFollowEntity by value, so when your function is called from main or from where ever! A copy of the object is made (using the copy constructor) and sent to the function ChangeFollowEntity, and after the completion of the execution of the function, your followEntity has the address of the COPY of the object, which gets destroyed after the completion of the function call, so your pointer followEntity is left dangling, which is undefined behavior if you access any entity using the followEntity
First is the correct way to do it!!
The second example does the following:
When the function is called a new Entity object newFollowEntiry
is created and whatever is passed into the function is used to
construct it
Then an address of that local stack based object is taken and
assigned to followEntiry to be stored presumably.
When the function execution is complete newFollowEntiry is destroyed
The folowEntity pointer is now pointing at a location in stack where
there is not Entity object anymore.
BUG
What does the second example exactly do here?
Your second example creates a Entity newFollowEntity which only exists for the duration of that function call.
The address of that variable is stored, and then the variable is destroyed, leaving a dangling pointer.
That's bad.
I am pretty sure I shouldn't be using a reference in this case because the followEntity changes, which references I believe cannot change
You can use a reference in this case. A referenced object can be changed - you are probably recalling that a reference cannot be reassigned.
int &sum(int numa, int numb)
{
int sum = 0;
sum = suma+sumb;
return sum;
}
Is this function correct? Why does it use &?
ADDED COMMENT:
thank you all. But after I compiled it using gcc, it came up one warning but no error. It can run perfectly. Still wrong? or just a warning issue? –
The & means you're returning a reference. In your case, you're returning a reference to an int, one that disappears as soon as the function returns; this is a serious bug.
This function tries to return a reference to an integer. Since the integer is local to the function, this definition is not valid; the integer will go out of scope once the function returns.
No you cannot return a reference to a local variable.
In addition to returning a reference to a local variable, which is evil incarnate, unless suma and sumb are declared at the global scope, the function is using names that don't exist.
Look up C++ References. It is not safe to return references (or pointers) to local variables. The local variable will be destroyed after the function exits and your returned pointer will point to undefined memory.
Since most of the above answers have cleared up the idea of a returned reference, I thought I would be a bit more precise with respect to the idea of it being "deallocated".
Functions calls place their arguments and automatic (locally declared) variables on the stack in memory. When a function returns, that memory is not zeroed out. The values are left alone, and that memory is reused for later functions as the stack grows.
So when you use this returned reference, it could be valid for a little bit, but then random data meant for other functions will write to the same spot, presenting you with garbage data.
& indicates that a reference to a variable is returned. This can help in cases where the original is a larger object because it saves having to make a copy of it in some cases.
However, I see no reason to do this for an int. In fact, since the original is deallocated when the function returns, it causes problems as you've used it here.
A pointer that is passed-in-by-reference. Why? aren't pointers just references anyways? What's really happening to this parameter?
void someFunc(MyPtr*& Object)
{
}
Simply speaking, it gives you the ability to change the pointer itself: it can be changed to point to another location in the function.
And the change will be reflected outside.
It enable you to:
void someFunc(MyPtr*& Object)
{
//Modify what Object is pointing to
Object=&old_Object;
//You can also allocate memory, depending on your requirements
Object=new MyPtr;
//Modify the variable Object points to
*Object=another_object;
}
Other's will have to vote to verify this cause I'm a bit rusty on my C++ but I believe the idea here is you'd pass in a pointer by reference, that is instead of creating a new space to store the pointer itself you use a reference to the pointer so if you were to modify the pointer not just the value it would be modified after returning from the function, whereas otherwise all you could do is modify the value at position passed in. Hope that makes sense.
The difference to passing just a pointer is that if the pointer is changed (Object = x) then this change will be seen by the calling function. You could achieve the same when you pass MyPtr** Object and dereference the pointer *Object = x;. With the second approach you could pass NULL to the function. This is not possible for references.
You are not quite right. The pointer content is passed by reference but the pointer itself is still passed by value, i.e. reassinging it to some other pointer will not be reflected upon the exit from the method because the pointer will be set to point to the same memory block as before the call. Think of it as a simple int variable. However with &* or ** you can reassign the pointer and that will be visible outside the scope of this method.
Why?
For the same reason that you would pass in anything else by reference.
aren't pointers just references anyways?
Dear god, no. Not even remotely the same thing. Look, you can try to build a mental model of a reference by starting with a pointer, but by the time you've fixed up all the differences, you have a horrible illogical mess.
References are a much simpler and more intuitive concept, and there are only "historical reasons" for trying to understand pointers before them. Modern C++ uses raw pointers only rarely, and treats them as an implementation detail as much as possible.
A reference is another name for an already-existing thing. That's it. When used as a function parameter, they thus allow the called function to refer to the caller's data.
It also means the pointer can be 0 (NULL) which can having meaning to the method. A reference must always be valid and cannot be made 'nothing'