I can use an object as pointer to it, or its reference. I understand that the difference is that pointers have to be deleted manually, and references remain until they are out of scope.
When should I use each of them? What is the practical difference?
Neither of these questions answered my doubts:
Pointer vs. Reference
C++ difference between reference, objects and pointers
A reference is basically a pointer with restrictions (has to be bound on creation, can't be rebound/null). If it makes sense for your code to use these restrictions, then using a reference instead of a pointer allows the compiler to warn you about accidentally violating them.
It's a lot like the const qualifier: the language could exist without it, it's just there as a bonus feature of sorts that makes it easier to develop safe code.
"pointers I have to delete and reference they remain until their scope finish."
No, that's completely wrong.
Objects which are allocated with new must be deleted[*]. Objects which are not allocated with new must not be deleted. It is possible to have a pointer to an object that was not allocated with new, and it is possible to have a reference to an object that was allocated with new.
A pointer or a reference is a way of accessing an object, but is not the object itself, and has no bearing on how the object was created. The conceptual difference is that a reference is a name for an object, and a pointer is an object containing the address of another object. The practical differences, how you choose which one to use, include the syntax of each, and the fact that references can't be null and can't be reseated.
[*] with delete. An array allocated with new[] must be deleted with delete[]. There are tools available that can help keep track of allocated resources and make these calls for you, called smart pointers, so it should be quite rare to explicitly make the call yourself, as opposed to just arranging for it to be done, but nevertheless it must be done.
suszterpatt already gave a good explanation. If you want a rule of thumb that is easy to remember, I would suggest the following:
If possible use references, use pointers only if you can not avoid them.
Even shorter: Prefer references over pointers.
Here's another answer (perhaps I should've edited the first one, but since it has a different focus, I thought it would be OK to have them separate).
When you create a pointer with new, the memory for it is reserved and it persists until you call delete on it - but the identifier's life span is still limited to the code block's end. If you create objects in a function and append them to an external list, the objects may remain safely in the memory after the function returns and you can still reference them without the identifier.
Here's a (simplified) example from Umbra, a C++ framework I'm developing. There's a list of modules (pointers to objects) stored in the engine. The engine can append an object to that list:
void UmbraEngine::addModule (UmbraModule * module) {
modules.push(module);
module->id = modules.size() - 1;
}
Retrieve one:
UmbraModule * UmbraEngine::getModule (int id) {
for (UmbraModule **it=modules.begin(); it != modules.end(); it++) {
if ((*it)->id == id) return *it;
}
}
Now, I can add and get modules without ever knowing their identifiers:
int main() {
UmbraEngine e;
for (int i = 0; i < 10; i++) {
e.addModule(new UmbraModule());
}
UmbraModule * m = e.getModule(5); //OK
cout << m << endl; //"0x127f10" or whatever
for (int j = 0; k < 10; j++) {
UmbraModule mm; //not a pointer
e.addModule(&mm);
}
m = e.getModule(15);
cout << m << endl; //{null}
}
The modules list persists throughout the entire duration of the program, I don't need to care about the modules' life span if they're instantiated with new :). So that's basically it - with pointers, you can have long-lived objects that don't ever need an identifier (or a name, if you will) in order to reference them :).
Another nice, but very simple example is this:
void getVal (int * a) {
*a = 10;
}
int main() {
int b;
getVal(&b);
return b;
}
You have many situations wherein a parameter does not exist or is invalid and this can depend on runtime semantics of the code. In such situations you can use a pointer and set it to NULL (0) to signal this state. Apart from this,
A pointer can be re-assigned to a new
state. A reference cannot. This is
desirable in some situations.
A pointer helps transfer owner-ship semantics. This is especially useful
in multi-threaded environment if the parameter-state is used to execute in
a separate thread and you do not usually poll till the thread has exited. Now the thread can delete it.
Erm... not exactly. It's the IDENTIFIER that has a scope. When you create an object using new, but its identifier's scope ends, you may end up with a memory leak (or not - depends on what you want to achieve) - the object is in the memory, but you have no means of referencing it anymore.
The difference is that a pointer is an address in memory, so if you have, say, this code:
int * a = new int;
a is a pointer. You can print it - and you'll get something like "0x0023F1" - it's just that: an address. It has no value (although some value is stored in the memory at that address).
int b = 10;
b is a variable with a value of 10. If you print it, you'll get 10.
Now, if you want a to point to b's address, you can do:
a = &b; //a points to b's address
or if you want the address pointed by a to have b's value:
*a = b; //value of b is assigned to the address pointed by a
Please compile this sample and comment/uncomment lines 13 and 14 to see the difference (note WHERE the identifiers point and to WHAT VALUE). I hope the output will be self-explanatory.
#include <iostream>
using namespace std;
int main()
{
int * a = new int;
int b = 10;
cout << "address of a: " << a << endl;
cout << "address of b: " << &b << endl;
cout << "value of a: " << *a << endl;
cout << "value of b: " << b << endl;
a = &b; //comment/uncomment
//*a = b; //comment/uncomment
cout << "address of a: " << a << endl;
cout << "address of b: " << &b << endl;
cout << "value of a: " << *a << endl;
cout << "value of b: " << b << endl;
}
Let's answer the last question first. Then the first question will make more sense.
Q: "What is the practical difference[ between a pointer and a reference]?"
A: A reference is just a local pseudonym for another variable. If you pass a parameter by reference, then that parameter is exactly the same variable as the one that was listed in the calling statement. However, internally there usually is no difference between a pointer and a reference. References provide "syntax sugar" by allowing you to reduce the amount of typing you have to do when all you really wanted was access to a single instance of a given variable.
Q: "When should I use each of em?"
A: That's going to be a matter of personal preference. Here's the basic rule I follow. If I'm going to need to manipulate a variable in another scope, and that variable is either an intrinsic type, a class that should be used like an intrinsic type (i.e. std::string, etc...), or a const class instance, then I pass by reference. Otherwise, I'll pass by pointer.
The thing is you cannot rebind a reference to another object. References are bound compile time and cannot be null or rebound. So pointers aren't redundant if your doubt was that :)
As my c++ teacher used to put it, pointers point to the memory location while references are aliases . Hence the main advantage is that they can be used in the same way as the object's name they refer to, but in a scope where the object is not available by passing it there.
While pointers can be redirected to some other location, references being like constant pointers, can't be redirected. So references cant be used for traversing arrays in a functions etc.
However a pointer being a separate entity takes up some memory, but the reference being the same as the referred object doesn't take any additional space. This is one of its advantages.
I have also read that the processing time for references are less,
as
int & i = b ;
i++ ; takes lesser time than
int * j = b ;
(*j) ++ ;
but I am yet to confirm this. If anyone can throw light on this claim it would be great.
Comments are welcome :)
Related
I apologise if the title is different from what I will be describing, I don't quite know how to describe it apart from using examples.
Suppose I have a shared_ptr of an object, and within that object, is a vector. I assign that vector to a variable so I can access it later on, and the shared_ptr gets destroyed as it goes out of scope. Question, is the vector I saved "safe" to access?
In the example below, from main(), outer() is called, and within outer(), inner() is called. inner() creates a shared_ptr to an object that contains a std::vector, and assigns it to a variable passed by reference. The role of outer() is to create some form of seperation, so that we know that the shared_ptr is destroyed. In main(), this referenced variable is accessed, but is it safe to use this variable?
#include <iostream>
#include <vector>
#include <memory>
struct sample_compound_obj {
std::vector<int> vektor;
sample_compound_obj(){std::cout << "I'm alive!" << std::endl;};
~sample_compound_obj(){std::cout << "Goodbye, thank you forever!" << std::endl;};
};
bool inner(std::vector<int>& input) {
std::cout << "About to create sample_compound_obj..." << std::endl;
std::shared_ptr<sample_compound_obj> hehe(new sample_compound_obj);
hehe->vektor.push_back(1);
hehe->vektor.push_back(2);
hehe->vektor.push_back(3);
input = hehe->vektor;
std::cout << "About to return from inner()..." << std::endl;
return true;
}
bool outer(std::vector<int>& input) {
std::cout << "About to enter inner()..." << std::endl;
inner(input);
std::cout << "About to return from outer()..." << std::endl;
return true;
}
int main() {
std::cout << "About to enter outer()..." << std::endl;
std::vector<int> vector_to_populate;
outer(vector_to_populate);
for (std::vector<int>::iterator it = vector_to_populate.begin(); it != vector_to_populate.end(); it++) {
std::cout << *it <<std::endl; // <-- is it even "safe" to access this vector
}
}
https://godbolt.org/z/47EWfPGK3
To avoid XY problem, I first thought of this issue when I was writing some ROS code, where a subscriber callback passes by reference the incoming message as a const shared_ptr&, and the message contains a std::vector. In this callback, the std::vector is assigned (via =) to a global/member variable, to be used some time later, after the end of the callback, so presumably the original shared_ptr is destroyed. One big difference is that in my example, I passed the std::vector by reference between the functions, instead of a global variable, but I hope it does not alter the behavior. Question is, is the std::vector I have "saved", suitable to be used?
is it safe to use this variable?
Yes, in the below statement, you copy the whole vector using the std::vector::operator= overload doing copy assignment. The two vectors do not share anything and live their separate lives and can be used independently of each other.
input = hehe->vektor;
In this case it's safe, because you get copy of the vector in this line:
input = hehe->vektor;
One big difference is that in my example, I passed the std::vector by reference between the functions, instead of a global variable, but I hope it does not alter the behavior.
Any reference can be bound only once, and in your scenario input reference is already bound to the argument passed (to be precise std::vector<int>& input of inner function is bound to std::vector<int>& input of outer function which itself is bound to std::vector<int> vector_to_populate). After a reference is bound, it acts as is object itself, so in the assignment statement you actually end up with calling something like this:
input.operator=(hehe->vektor);
Where operator= refers to the std::vector<T>::operator=(const std::vector<T> rhs) function.
If you're familiar with the RAII concept and C++ references, you can pretty much skip the following explanations
In C++, vectors, and as a matter of fact, pretty much all structs, defined in std work very differently from what you might be used to in other higher level languages, like Java or C#. In C++, the RAII (resource acquisition is initialization) technique is used. I highly recommend that you actually read the article, but in short, it means that an object will define a constructor and a destructor, that allocate and free all memory used by the object, in your case, a std::vector, and the language is going to call the destructor when the object falls out of scope. This ensures that there are no memory leaks.
However, how would we go about passing a std::vector to a function, for example? Well, if we just made a straight up copy of the object, byte by byte, as we'd do in C, the function would run fine, until we reach the end of the function, and we call the destructor of the vector. In that case, after the function executes, when we go back to the caller, the vector is no longer valid, because its data got freed by the callee.
void callee(std::vector<int> vec) { }
void caller() {
std::vector<int> vec;
vec.push_back(10);
callee(vec);
vec.push_back(10); // This will break, with our current logic
}
Well, the keyword here is "copy". We copied the vector so that we can pass it in the callee function. We can solve this issue by creating custom copy behavior, in C++ terms that would be a copy constructor. In simple terms, a copy constructor takes an instance of the type itself as an argument, and copies it in the current instance. This allows us now to execute the code from above without any issues.
There are a lot more intricacies to it than I've written here, but other people have said it better than I have. In short, whenever you try to make an assignment, or pass an argument, you utilize the copy constructor (with some exceptions). In your case, you assign a vector variable with a vector value. This vector value gets copied, and so is valid until the function goes out of scope. There is a catch to that thou: if you try to modify the vector, you will modify only the copy, not the original. If you want to do so, you'll need to utilize references.
In C++, we have the concept of references. You can consider the reference something like a pointer, with some caveats to it. First of all, unlike pointers, you can't have a reference to a reference. The reference tells C++ that you don't work with the object itself, but an "alias" of the object. The object will exist in one place in the memory, but you will be able to access it in two places:
int a = 10;
int &ref_a = a;
std::cout << ref_a << ", " << a << "\n"; // 10, 10
ref_a = 5;
std::cout << ref_a << ", " << a << "\n"; // 5, 5
a = 8;
std::cout << ref_a << ", " << a << "\n"; // 8, 8
In the line int &ref_a = a, we don't actually copy a, but we tell ref_a that it is a reference of a. This means that any operations (including assignment) will be applied to a, not to ref_a. We can use references with variables, fields, return values and parameters. A reference is valid as long as the value it refers to is valid, so as soon as the value goes out of scope, the reference is no longer valid.
References can be used in parameters, in order to avoid copying the value. This can provide a lot of performance benefits, since we don't need to copy the value, but just pass a "pointer" to it. Of course, this means that if the function modifies the parameter, that is reflected in the caller:
void func(int &ref) {
ref = 5;
}
void func2() {
int a = 10;
func(a);
std::cout << a; // 5
}
TL; DR
In your case, you're returning a vector via an out parameter (reference parameter). Still, even if you're working with references, setting a reference will actually set the object behind the reference, and will use the copy constructor of the object. You can avoid that by making that a reference of a pointer to a vector, but working with pointers in C++ is strongly advised against. Regardless, the answer to your question is that this code is completely safe. Still, if you try to modify input in outer, you won't modify the vector in hehe, but instead you're going to modify the copy that inener has created.
What is a safe way to accessing member variables through a shared object in C++?
In the code below, I make a shared variable and then a pointer to a member variable of it. However, the use_count remains unchanged and when I reset the shared variable the original variable is reset but not the pointer to member.
In other words, I could introduce some bugs by using b. The object it is pointing to shouldn't exist anymore.
#include <iostream>
#include <memory>
using namespace std;
struct A
{
int y;
A(int x)
{
y = x;
}
};
int main()
{
auto a = make_shared<A>(1);
cout << "a count: " << a.use_count() << endl; //prints a count: 1
auto b = a->y;
cout << "a count: " << a.use_count() << endl; //still prints a count: 1
a.reset();
cout << "a value: " << a << endl; //prints a value: 0
cout << "b value: " << b << endl; //prints b value: 1
return 0;
}
auto b = a->y;
This will copy the value of y, so it's not a pointer to y, it's only a copy.
auto a = make_shared<A>(1);
auto b = std::shared_ptr<int>(a, &a->y);
b is a shared pointer to y that does what you want.
This is known as the "aliasing constructor" of shared ptr. It is intended for exactly this purpose; having a shared pointer into part of a larger shared ptr.
You can use it for lots of insane and fancy things on top of it. Be careful when using it, as you can get strange states like empty non-null shared ptrs, and non-empty null shared ptrs. But if you use it "normally" like the above, it will work fine.
What you did
auto a = make_shared<A>(1);
auto b = a->y;
simply copies y into b, no pointers are involved.
What is a safe way to accessing member variables through a shared object in C++?
You are already doing it. The code you showed is safe.
In the code below, I make a shared variable and then a pointer to a member variable of it.
No, you don't. A::y is an int. In the auto b = a->y; statement, auto deduces to int, not to int& or int*. So, you are creating a new int whose value is a copy of y. There is no pointer to y.
If you wanted something like that, you would have needed to use one of these instead:
auto &b = a->y;
...
cout << "b value: " << b << endl;
auto *b = &(a->y); // or just: auto b = ...
...
cout << "b value: " << *b << endl;
However, the use_count remains unchanged
Correct, because you are not assigning a to another instance of shared_ptr<A>. That is what use_count represents - the number of shared_ptr objects that are sharing the same object in memory.
when I reset the shared variable the original variable is reset but not the pointer to member.
Of course, because b is independent of a and is not a pointer to anything related to a.
In other words, I could introduce some bugs by using b.
No, because b is not linked to a, so resetting a has no effect on b.
Now, if you did manage to accomplish what you are asking for (making b be a pointer to y), it is your responsibility to make sure the A object that y was accessed from remains valid in memory until you are done using b, otherwise dereferencing b will be undefined behavior. The STL won't save you from doing something stupid behind its back, like accessing an A object's member via a raw pointer after the object has been destroyed.
The moral of the story is don't hand out references to objects that may die before the reference. Design with every object's life-span in mind. One solution may be to copy the std::shared_ptr to make sure the reference is always pointing at the object another solution might be to pass a std::weak_ptr when you don't need the object to still be valid but you need to know so you don't try to use it. Only pass out pointers and references when you know the object will outlive them.
I am working through a c++ book/guide, but the pointers and references seem a little vague to me. This is coming from myself as a C# programmer and c# mindset that uses
foo(ref int x) and bar(out int y)
A small piece of code I wrote to show the memory position and memory position value, but I do not fully understand what each means, and in what context this is in.
int main()
{
int i = 50;
foo(&i);
cout << "\n\n" ;
foo(i);
getchar();
return 0;
}
void foo(int& bar) // & refer
{
cout << "refer";
cout << "\n&bar = " << &bar;
cout << "\nbar = " << bar;
}
void foo(int* bar)// * pointer
{
cout << "prefer";
cout << "\n&bar = " << &bar;
cout << "\nbar = " << bar;
}
output shows:
pointer
&bar = 0018FC30
bar = 0018FD04
refer
&bar = 0018FD04
bar = 50
What does & and * in each case mean, and how does it affect the output?
ofcourse, I have added all necessary methods into the .h file
UPDATE AFTER READING SOME ANSWERS
int i (values from pointer, aka points directly to variable)
has a value = 50
has an memory address = 0018FD04
pointer which points to int i
has a value which is int i memory address = 0018FD04
has its own memory address = 0018FC30
thus, to clarify, using a "refer" or "&bar" in the example actually creates a new variable which duplicates the int i passed through in the foo(int& bar).
Instead of the new &bar value containing the 50, it will have the memory address of the int i.
TL;DR
foo(int bar) receives the "value" of the variable
foo(int* bar) receives the "value" of the variable, if changed, it will change the variable in the calling method.
foo(int& bar) receives the pointer/memory address of the variable.
I hope others find this as useful as I did, thank you all!
Okay, the pointer first :
void foo(int* bar)// * pointer
{
cout << "prefer";
cout << "\n&bar = " << &bar;
cout << "\nbar = " << bar;
}
You're calling it with
int i = 50;
foo(&i);
In this context, *bar will be 50 (get the value the int pointer is pointing to).
&bar is the address of the pointer that is created ( the pointer itself needs a place in memory too of course ).
bar is the address of the object the pointer is pointing to ( i in this case )
Reference case:
void foo(int& bar) // & refer
{
cout << "refer";
cout << "\n&bar = " << &bar;
cout << "\nbar = " << bar;
}
Here, bar will refer to i that you created in main. &bar will return the address of i and bar it's value, 50 in this case. References themselves don't have their own addresses.
Coming from C#, pointers can be thought of like classes, while values act more like structs - when you alter their members, you're either altering a copy (in the case of pass-by-value objects, which is not shown), altering the same object you've been passed (in the case of pass-by-pointer), or altering the same value including the reference to the actual value you've been passed (in the case of pass-by-reference). In other words, instead of the object's declaration controlling how it's passed, the implementation decides how it's passed.
For each method header, behavior is as follows:
void foo(int& bar) // & refer
When you pass using type& name, you're passing by reference, and you're passing the equivalent of C#'s ref (or out if you didn't give the variable a meaningful value to begin with). Even though you've passed a value, changes to the value, including changing the value itself, will be reflected in the calling scope.
void foo(int* bar)// * pointer
When you pass an object using type* name, you're passing the pointer to that object. You are, however, passing the pointer as a value, so while you could change members (moot in the case of an int) you could not change the value (bar) itself. Again like C#, this would be like passing a class object without the use of ref/out - reassignment won't be reflected in the calling scope.
Going over the use of & in code...
cout << "\n&bar = " << &bar;
In this case, & the "address-of" operator. Whenever you take &variable in code, you're going to get the memory address of that variable - printing this value will give your the hexadecimal address the variable lives in RAM, which is basically gibberish in all but the most technical debug and sample cases. This also applies to pointers - you can take the pointer of a pointer (of a pointer of a pointer... ad infinitum).
In C++ the default is pass by value. So if you have a f(X x) then the compiler is going to generate code that copies the class X every time you call the function. If X is large (like an array, string, map or something like that) you probably don't want a copy, for performance reasons. Making a copy also means that if you modify the parameter inside your function you only modify the copy so it won't be visible after you return.
Now to make things visible outside of the function you must modify the instance of the caller. To do this you must have a pointer(*) or a reference(&) to that instance. The immediately visible difference between the two is that you can compare the pointer to nullptr (it's more tricky for the reference), that for the pointer you must use -> to access it's members, vs . for the reference and that when calling you must take the address of the argument to get the pointer (f(&global_x)). In general you should use references where there argument can never be nullptr. You should prefer pointer when it's reasonable to call the function with that argument missing. These are equivalent with C# ref or out. There are more subtle differences between the two but they only become apparent if you are writing templates and libraries.
If you want to avoid the copy but you don't want to modify the argument you should use const, which asks the compiler to make sure that you don't accidentally modify the value. You can use it with both references and pointers.
Picking references vs. pointers is most of the time a ting of coding style. The most important thing is to be consistent because it is annoying having to lookup function definitions all the time to see if you used pointers or references that one time.
I am working through a c++ book/guide, but the pointers and references seem a little vague to me
You'll find plenty of explanations for this if you try searching, but here is my attempt.
A pointer is a variable that tells you where to find another variable, by pointing to it. A pointer is really just a number that corresponds to the address in memory of another variable. Examples of addresses are the 0018FC30 and 0018FD04 in your output.
A reference is an alias (another name for) a variable. If you have a variable a and you create a reference b to it, b becomes an alternative name for a.
The value of a reference is not an address like for a pointer, it's the value of whatever it refers to.
The interest of references is that when you copy them or pass them around, you're not copying the actual value (which can be expensive), you're only copying the name.
The main observable difference is that you can change what a pointer points to (by changing the value of a pointer, since its value is really just an address), but you can't change what a reference refers to (in a way, it becomes what it refers to).
What does & and * in each case mean, and how does it affect the output?
When you have a variable a, the expression &a means "take the address of a".
This is interesting, because if you have the address of a variable, you can make a pointer point to it.
And *a could be seen as more or less the inverse operation, if you have a pointer a, *a means "take the value at the address this pointer points to".
You can use &a on anything that has an address. You could even take the address of a pointer to create a pointer-to-pointer! But you can only use *a on something that behaves like a pointer, it would be meaningless otherwise.
Imagine we have:
int* a; // This holds memory addresses
a = new int;
cout << a; // This will print the memory address of your new int
cout << *a; // This will print the value at the memory address a is holding
cout << &a; // This will print the memory address of the pointer variable.
If you declare a function that takes a pointer as a parameter, you should pass a pointer and not a static variable.
I hope this helped you even if its just a little bit.
Many programmers advocate the use of make_shared because it reduces typing and reduces programming errors. However there are some cases where using the constructors of shared_ptr is unavoidable. One of these cases is when you have an existing pointer that you want shared_ptr to own, since shared_ptr<Foo>(&existing_ptr) is bad code. Instead, you have to use the unwieldy shared_ptr<Foo>(shared_ptr<Foo>(), p). Not only are you repeating yourself, but you have to create a temporary object.
int main()
{
using namespace std;
Foo foo;
foo.n = 1;
{
auto ptr = make_shared<Foo>(move(foo));
ptr->n = 42;
cout << ptr->n << " " << foo.n << '\n';
}
{
auto p = &foo;
auto ptr = shared_ptr<Foo>(shared_ptr<Foo>(), p);
ptr->n = 42;
cout << ptr->n << " " << foo.n << '\n';
}
return 0;
}
Foo::Foo()
Foo::Foo(Foo &&)
42 1
Foo::~Foo()
42 42
Foo::~Foo()
What's a less verbose way to have shared_ptr own an existing pointer?
The intended use of that constructor is to allow shared pointers to sub objects of shared pointers.
Your use is not the intended use, and is quite dangerous, as you have implicitly created a guarantee that the data you are passing to the shared pointer will last as long as the shared pointer or its copies does, and then failing to enforce that guarantee in any meaningful sense.
If you pass a shared pointer to a function, it has every right to cache a copy if it and use it 15 minutes later. And if you aren't passing a shared pointer to a function, you don't need one.
In general, a function should only require a shared pointer if it intends to extend the lifetime of its argument in a difficult to predict way. So if you have a function that takes a shared pointer and never extends its lifetime (or the lifetime of a pointer to it), it should not be taking a shared pointer. The problem is in the function you are calling, not with how you have to jump through hoops to call it.
Only when you both have a function that is broken, and are unable to fix it and making a copy of Foo on the free store is overly expensive, is your technique worth trying. And that should be extreme corner cases anyhow.
IMO what you're doing there shouldn't be easy because it's very dangerous, and only necessary under highly specialized circumstances where typing a class name twice should be the least of your worries.
But here is a slightly more succinct way to achieve the same thing by using a dummy deleter:
auto ptr = std::shared_ptr<Foo>(&foo, [](void*){});
Also, in your approach it isn't really correct to say that ptr owns foo; rather it owns the null object in the empty std::shared_ptr<Foo> and points to foo (see this answer for a longer discussion). In my code above it does "own" foo in some technical sense (or at least it thinks it does); it's just been prevented from doing anything to it when its reference count reaches zero.
Being that my C++ isn't that great, this may be a really simple/obvious answer, but it sure has me stumped. Keep in mind its kinda late here and I'm a little tired. I got this code here:
void TestFunc(int *pVar)
{
cout << endl << *pVar << endl;
delete pVar;
pVar = nullptr;
}
int main(int argc, char *argv[])
{
int *z(new int);
*z = 5;
TestFunc(z);
if (z == nullptr)
cout << "z Successfully Deleted!" << endl;
else cout << "z NOT deleted!" << endl;
return 0;
}
The program compiles just fine with no errors or warning. When I run it, it displays 5, just as I'd expect. However, it says z NOT deleted!. I am curious as to why pVar is not getting set to nullptr even though I explicity set it in my TestFunc() function. Any help would be appreciated. If it matters, this is Visual Studio 2010 and just a regular unmanaged C++ application.
Because it's being passed by value (i.e. as a copy).
If you want the variable itself to be passed (rather than just its value, which is copied), use
void TestFunc(int *&pVar)
instead.
Note that delete only cares about the pointee, not the pointer. So "deleting" a copy of a pointer deletes the same thing as the original pointer, because in either case you're deleting their targets, which are the same.
TestFunc accepts the pointer by value, so setting it to null inside the function actually only affects the copy in the function and is not visible to the caller. So pVar is set to null, but z in main() is not because those are different variables.
To make the change visible to the caller pass the pointer by reference or via a double pointer.
It is late (sorry!!!).
z is passed by value. z is not pVar. You assigned the value of nullptr to pVar and not to z.
The "idiom" you present is generally advocated as Safe Delete.
It was already known in C (though it was a free back then): zero-out the pointer you just freed / deleted to avoid doing so twice.
The trouble is, you zero out the current pointer, but any copy of it still point to the same memory area, which now contains garbage.
Memory handling is a difficult topic, the fundamental concept is ownership. At any point in time, the owners of a particular memory zone should be well identified, and they should have the responsibility of returning it to the system when appropriate.
The first step in this direction is the use of smart pointers, for example std::unique_ptr or boost::scoped_ptr. For shared ownership (experts only), std::shared_ptr might come handy, but you're not there yet.
If you write a delete in your code, it means you are exposing yourself to leaks. It is not bad in itself, but it calls for careful review, and makes the code brittle (ie, likely to break on change). In your case:
int main() {
boost::scoped_ptr<int> i(new 5);
foo(*i);
} // memory returned to system by ~scoped_ptr()