In a couple of my older code projects when I had never heard of smart pointers, whenever I needed to check whether the pointer still pointed to a valid object, I would always do something like this...
object * meh = new object;
if(meh)
meh->member;
Or when I needed to delete the object safely, something like this
if(meh)
{
delete meh;
meh = 0;
}
Well, now I have learned about the problems that can arise from using objects and pointers in boolean expressions both with literal numbers, the hard way :. And now I've also learned of the not so new but pretty cool feature of C++, the nullptr keyword. But now I'm curious.
I've already gone through and revised most of my code so that, for example, when deleting objects I now write
if(meh)
{
delete meh;
meh = nullptr;
}
Now I'm wondering about the boolean. When you pass just say an int into an if statement like this,
int meh;
if(meh)
Then it implicitly checks for zero without you needing to write it.
if(meh == 0) // does the exact same check
Now, will C++ do the same for pointers? If pass in a char * like this to an if statement?
char * meh;
if(meh)
Then will it implicitly compare it with nullptr? Because of how long I have been writing these ifs like this, it is second nature at this point to check if the pointers valid before using by typing if (object *) and then calling its members. If this is not the functionality why not? Too difficult to implement? Would solve some problems by removing yet another tiny way you could mess up your code.
In C, anything that's not 0 is true. So, you certainly can use:
if (ptrToObject)
ptrToObject->doSomething();
to safely dereference pointers.
C++11 changes the game a bit, nullptr_t is a type of which nullptr is an instance; the representation of nullptr_t is implementation specific. So a compiler may define nullptr_t however it wants. It need only make sure it can enforce proper restriction on the casting of a nullptr_t to different types--of which boolean is allowed--and make sure it can distinguish between a nullptr_t and 0.
So nullptr will be properly and implicitly cast to the boolean false so long as the compiler follows the C++11 language specification. And the above snippet still works.
If you delete a referenced object, nothing changes.
delete ptrToObject;
assert(ptrToObject);
ptrToObject = nullptr;
assert(!ptrToObject);
Because of how long I have been writing these ifs like this, it is second nature at this point to check if the pointers valid before using by typing if (object *) and then calling it's members.
No. Please maintain a proper graph of objects (preferably using unique/smart pointers). As pointed out, there's no way to determine if a pointer that is not nullptr points to a valid object or not. The onus is on you to maintain the lifecycle anyway.. this is why the pointer wrappers exist in the first place.
In fact, because the life-cycle of shared and weak pointers are well defined, they have syntactic sugar that lets you use them the way you want to use bare pointers, where valid pointers have a value and all others are nullptr:
Shared
#include <iostream>
#include <memory>
void report(std::shared_ptr<int> ptr)
{
if (ptr) {
std::cout << "*ptr=" << *ptr << "\n";
} else {
std::cout << "ptr is not a valid pointer.\n";
}
}
int main()
{
std::shared_ptr<int> ptr;
report(ptr);
ptr = std::make_shared<int>(7);
report(ptr);
}
Weak
#include <iostream>
#include <memory>
void observe(std::weak_ptr<int> weak)
{
if (auto observe = weak.lock()) {
std::cout << "\tobserve() able to lock weak_ptr<>, value=" << *observe << "\n";
} else {
std::cout << "\tobserve() unable to lock weak_ptr<>\n";
}
}
int main()
{
std::weak_ptr<int> weak;
std::cout << "weak_ptr<> not yet initialized\n";
observe(weak);
{
auto shared = std::make_shared<int>(42);
weak = shared;
std::cout << "weak_ptr<> initialized with shared_ptr.\n";
observe(weak);
}
std::cout << "shared_ptr<> has been destructed due to scope exit.\n";
observe(weak);
}
Now, will C++ do the same for pointers? If pass in a char * like this to an if statement?
So to answer the question: with bare pointers, no. With wrapped pointers, yes.
Wrap your pointers, folks.
It's not possible to test whether a pointer points to a valid object or not. If the pointer is not null but does not point to a valid object, then using the pointer causes undefined behaviour. To avoid this sort of error, the onus is on you to be careful with the lifetime of objects being pointed to; and the smart pointer classes help with this task.
If meh is a raw pointer then there is no difference whatsoever between if (meh) and if (meh != 0) and if (meh != nullptr). They all proceed iff the pointer is not null.
There is an implicit conversion from the literal 0 to nullptr .
It is always set a pointer to zero after invalidating it so that you know a pointer that's non-zero is valid" is an anti-pattern. What happens if you have two pointers to the same object? Setting one to zero won't be better and it does not affect the other.
Related
I'm going through some tutorials on how smart pointers work in C++, but I'm stuck on the first one I tried: the unique pointer. I'm following guidelines from wikipedia, cppreference and cplusplus. I've also looked at this answer already. A unique pointer is supposed to be the only pointer that has ownership over a certain memory cell/block if I understood this correctly. This means that only the unique pointer (should) point to that cell and no other pointer. From wikipedia they use the following code as an example:
std::unique_ptr<int> p1(new int(5));
std::unique_ptr<int> p2 = p1; //Compile error.
std::unique_ptr<int> p3 = std::move(p1); //Transfers ownership. p3 now owns the memory and p1 is rendered invalid.
p3.reset(); //Deletes the memory.
p1.reset(); //Does nothing.
Until the second line, that worked fine for me when I test it. However, after moving the first unique pointer to a second unique pointer, I find that both pointers have access to the same object. I thought the whole idea was for the first pointer to be rendered useless so to speak? I expected a null pointer or some undetermined result. The code I ran:
class Figure {
public:
Figure() {}
void three() {
cout << "three" << endl;
}
};
class SubFig : public Figure {
public:
void printA() {
cout << "printed a" << endl;
}
};
int main()
{
unique_ptr<SubFig> testing (new SubFig());
testing->three();
unique_ptr<SubFig> testing2 = move(testing);
cout << "ok" << endl;
int t;
cin >> t; // used to halt execution so I can verify everything works up til here
testing->three(); // why is this not throwing a runtime error?
}
Here, testing has been moved to testing2, so I'm surprised to find I can still call the method three() on testing.
Also, calling reset() doesn't seem to delete the memory like it said it would. When I modify the main method to become:
int main()
{
unique_ptr<SubFig> testing (new SubFig());
testing->three();
unique_ptr<SubFig> testing2 = move(testing);
cout << "ok" << endl;
int t;
cin >> t;
testing.reset(); // normally this should have no effect since the pointer should be invalid, but I added it anyway
testing2.reset();
testing2->three();
}
Here I expect three() not to work for testing2 since the example from wikipedia mentioned the memory should be deleted by resetting. I'm still printing out printed a as if everything is fine. That seems weird to me.
So can anyone explain to me why:
moving from one unique pointer to another unique pointer doesn't make the first one invalid?
resetting does not actually remove the memory? What's actually happening when reset() is called?
Essentially you invoke a member function through a null pointer:
int main()
{
SubFig* testing = nullptr;
testing->three();
}
... which is undefined behavior.
From 20.8.1 Class template unique_ptr (N4296)
4 Additionally, u can, upon request, transfer ownership to another
unique pointer u2. Upon completion of such a transfer, the following
postconditions hold:
u2.p is equal to the pre-transfer u.p,
u.p is equal to nullptr, and
if the pre-transfer u.d maintained state, such state has been transferred to u2.d.
(emphasis mine)
After the std::move() the original pointer testing is set to nullptr.
The likely reason std::unique_ptr doesn't check for null access to throw a runtime error is that it would slow down every time you used the std::unique_ptr. By not having a runtime check the compiler is able to optimize the std::unique_ptr call away entirely, making it just as efficient as using a raw pointer.
The reason you didn't get a crash when calling the nullptr is likely because the function you called doesn't access the (non-existent) object's memory. But it is undefined behavior so anything could happen.
On calling std::unique_ptr<int> p3 = std::move(p1); your original pointer p1 is in undefined state, as such using it will result in undefined behavior. Simply stated, never ever do it.
Maybe this question has been asked before, but I've never found a satisfactory answer. Also, for the purposes of simplicity assume I'm talking about a single-threaded application.
So, what I've heard a number of times is that if you have an object that is non-owned and whose lifetime is guaranteed, you should reference it with a raw pointer. The object's owner would use a unique_ptr, and hand out raw pointers as necessary.
But what if the object is non-owned, and the lifetime is not guaranteed? Then you can use a weak_ptr, yes. But then anyone who is handed a weak_ptr could be naughty and keep it locked, such that the object's owner can't cause the object to be destroyed. Sometimes this may not be a problem, but sometimes it is. For example, when the owned object represents some system resource which must be relinquished at a certain time.
You may say "well, then you should just make sure no one keeps the weak_ptr locked!" But that is just not ideal (in my opinion) from an OO design standpoint, as it creates a dependency between the "owner" object and any object that gets a weak_ptr from it. You might as well make the argument "you don't need to return const references; you should just make sure no one modifies the reference."
With Qt, you have the QPointer, which is basically what I'm looking for. It checks that the object hasn't been destroyed, but it can't prevent the object from being destroyed. I realize this isn't thread-safe, but again, I'm talking about the context of a single thread.
So why isn't there something similar for C++11? I'm sure I could make a wrapper around weak_ptr that accomplishes what I'm after. But I wonder if I'm going about this all wrong.
No. And it doesn't exist is because it's unsafe even for a single thread. Consider:
void some_function (super_weak_ptr foo)
{
foo->some_function();
}
What happens if some_function (through an indirect path) causes the object to be destroyed? And before you say that can never happen, yes it can. For example:
void got_some_data (some_type whatObject, some_other_type whatData)
{
super_weak_ptr object = findObject (whatObject);
if (object)
object->youGotMail (whatData);
}
Now, suppose the youGotMail function realizes that the object now got the last bit of data it needs and its job is complete, it might destroy that object, and now we're running a function on an object that no longer exists.
If you want a raw pointer, you know where to find one. It doesn't make much sense to create a "smart" pointer that's no safer than a raw pointer.
So if you're not managing the lifetime of an object, you need the ability to lock that object before you can do anything to that object.
You can do this with pure Standard C++ using shared_ptr<unique_ptr<T>>.
Observers received only a shared_ptr<const unique_ptr<T>>, allowing them to look but not touch. The owner, having a non-const smart pointer, can at any time call reset() on the unique_ptr to destroy the instance. At that time all the observers can also see that the unique_ptr has become empty.
Obvious threading and re-entrance caveats apply (you need to check the unique_ptr for having a valid pointer again after each callback you invoke, etc).
And if there should be multiple owners, it's a bit more work. You will need one shared_ptr<T*>, giving observers a shared_ptr<T* const>. And a separate shared_ptr<T> to manage the object lifetime. The shared_ptr<T*> will need to be manually filled with nullptr (The T*, not the shared_ptr) in the object's destructor.
There is no such thing, alas.
In 2009 I toyed with / explored such a smart pointer type that I called ZPtr, as I recall as a cleanup effort of some earlier code in that direction, in the context of supporting better file abstraction error handling than the silence treatment of the standard library's iostreams. The (earlier) idea was to not have any zombie objects around, by self-destroying when no further meaningful operations were possible, and this required access via a smart pointer that could detect the existence or not of the referent. Evidently it was not such a good idea at the time, because the article I sent to DDJ about it was rejected … by the silence treatment.
I think now that we have argument forwarding support in the language, the time for such a pointer may have come. It would be even better with possible overloading of the . operator. But the functionality will anyway have to be chosen very carefully.
The std::weak_ptr isn't really "locked", in spite of naming. It's just used to obtain a std::shared_ptr, if possible. And a std::shared_ptr readily supplies you with a raw pointer.
So you can choose to hand out not std::weak_ptr directly, but a wrapper that only provides a temporary raw pointer.
It will not be very thread safe though, and unlike a ZPtr it will not give the client code any idea of why the referent doesn't exist any more (when it doesn't). But it just may be all that you need. Let me get some coffee & a bite to eat, then I'll cook up an example.
Example:
#include <memory>
namespace cppx {
using std::shared_ptr;
using std::weak_ptr;
template< class Type >
class Poor_ptr
{
private:
struct Null {};
weak_ptr<Type> weak_p_;
public:
explicit operator bool() const { return not is_null(); }
friend
auto operator==( const Poor_ptr& p, Poor_ptr::Null* )
-> bool
{ return p.is_null(); }
friend
auto operator==( Poor_ptr::Null*, const Poor_ptr& p )
-> bool
{ return p.is_null(); }
friend
auto operator!=( const Poor_ptr& p, Poor_ptr::Null* )
-> bool
{ return not p.is_null(); }
friend
auto operator!=( Poor_ptr::Null*, const Poor_ptr& p )
-> bool
{ return not p.is_null(); }
auto is_null() const
-> bool
{ return (ptr_or_null() == nullptr); }
auto ptr_or_null() const
-> Type*
{
try
{
return weak_p_.lock().get();
}
catch( ... )
{
return nullptr;
}
}
auto ptr() const
-> Type*
{ return weak_p_.lock().get(); }
Poor_ptr( shared_ptr< Type > p )
: weak_p_( p )
{}
};
} // namespace cppx
#include <iostream>
using namespace std;
auto main() -> int
{
cout << boolalpha;
auto p = make_shared<int>( 42 );
cppx::Poor_ptr<int> pp = p;
cout
<< "That " << pp.ptr_or_null() << " is null is "
<< (pp == 0) << ", not " << !!pp << ".\n";
p.reset();
cout
<< "That " << pp.ptr_or_null() << " is null is "
<< (pp == 0) << ", not " << !!pp << ".\n";
}
Oh, and to cover the problem that David Schwartz mentions, that of the object disappearing in mid-call of some function, you can just provide a member function that executes a functor such as std::function with a raw pointer as argument, where the referred to object is guaranteed kept alive during that call (namely by having a local std::shared_ptr).
Then the client code programmer can choose whether to rely on an assumption that called functions will not destroy the object, or use the safer callback mechanism.
New to this kind of stuff, probably doing something wrong, but -
I have 3 members
std::unique_ptr<Gun> currentWeapon;
std::unique_ptr<Gun> weaponSlotOne;
std::unique_ptr<Gun> weaponSlotTwo;
Gun is a base class that has other derived classes such as Pistol and SMG.
What i'm doing is setting weaponSlotOne and weaponSlotTwo to two different guns, then setting currentWeapon to the first weapon.
weaponSlotOne.reset(new DevPistol());
weaponSlotTwo.reset(new AutoDevPistol());
currentWeapon = std::move(weaponSlotOne);
and i have a switchWeapons method, that does this:
void Player::switchWeapons() {
if(currentWeapon == weaponSlotOne) {
currentWeapon = std::move(weaponSlotTwo);
}
else {
currentWeapon = std::move(weaponSlotOne);
}
}
which seems to destroy/deallocate both guns for some reason. i'm not quite sure what's going wrong.
The problem is that after calling std::move on an object, the object is in an indeterminate state, and you can't safely do anything with the object other than destroy it or assign to it.
In your case, after doing currentWeapon = std::move(weaponSlotOne);, weaponSlotOne is indeterminate, so when you test currentWeapon == weaponSlotOne you might get any result. Probably, this will be false (weaponSlotOne will be null), so you'll just copy it to currentWeapon, dropping whatever was there (deleting it).
The question is, what are you trying to do? If you want two weapons, and want to keep track of which one is current, it might make more sense to do:
std::unique_ptr<Gun> *currentWeapon;
std::unique_ptr<Gun> weaponSlotOne;
std::unique_ptr<Gun> weaponSlotTwo;
weaponSlotOne.reset(new DevPistol());
weaponSlotTwo.reset(new AutoDevPistol());
currentWeapon = &weaponSlotOne;
void Player::switchWeapons() {
if(currentWeapon == &weaponSlotOne) {
currentWeapon = &weaponSlotTwo;
}
else {
currentWeapon = &weaponSlotOne;
}
}
Or even more simply:
std::unique_ptr<Gun> weaponSlot[2];
int currentWeapon = 0;
void Player::switchWeapons() {
currentWeapon ^= 1;
}
In general, after moving from an object the moved-from object is in a valid but unspecified state. This means that you can only safely call those functions on the moved-from object which have no preconditions. For example destruction typically has no precondition. Typically neither does assigning to an object. And typically neither do const observers such as equality comparison with a non-moved from value.
In the case of std::unique_ptr, you can safely compare a moved-from value. But also note that unique_ptr has unique ownership semantics. I.e. two non-null unique_ptrs should never compare equal, because if they did, they would own the same pointer, and thus be in violation of the basic tenant of unique_ptr. But it often makes sense to compare unique_ptr with nullptr to find out if it owns a non-null pointer:
#include <cassert>
#include <memory>
int
main()
{
std::unique_ptr<int> p(new int(3));
auto p2 = std::move(p);
assert(p == nullptr); // perfectly legal & practical use of moved-from value
}
I suspect the problem with your code is/was that you were mistakenly expecting copy semantics from the unique_ptr move assignment: i.e. that the source of the assignment would be left unchanged. However from my code snippet above it can be shown that the moved-from unique_ptr will be reliably left equal to nullptr. There simply is no other way to implement the operation while still satisfying all unique_ptr specifications.
Just in case anyone ever makes it to this post. You can use the std::swap on shared or unique pointer.
http://www.cplusplus.com/reference/memory/shared_ptr/swap/
edit:
try to avoid code like:
weaponSlotOne.reset(new DevPistol());
It can cause memory leaks. Better would be:
weaponSlotOne = std::make_unique<DevPistol>();
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()
I've mostly only worked with C and am running into some unfamiliar issues in C++.
Let's say that I have some function like this in C, which would be very typical:
int some_c_function(const char* var)
{
if (var == NULL) {
/* Exit early so we don't dereference a null pointer */
}
/* The rest of the code */
}
And let's say that I'm trying to write a similar function in C++:
int some_cpp_function(const some_object& str)
{
if (str == NULL) // This doesn't compile, probably because some_object doesn't overload the == operator
if (&str == NULL) // This compiles, but it doesn't work, and does this even mean anything?
}
Basically, all I'm trying to do is to prevent the program from crashing when some_cpp_function() is called with NULL.
What is the most typical/common way of doing this with an object C++ (that doesn't involve overloading the == operator)?
Is this even the right approach? That is, should I not write functions that take an object as an argument, but rather, write member functions? (but even if so, please answer the original question)
Between a function that takes a reference to an object, or a function that takes a C-style pointer to an object, are there reasons to choose one over the other?
Basically, all I'm trying to do is to
prevent the program from crashing when
some_cpp_function() is called with
NULL.
It is not possible to call the function with NULL. One of the purpose of having the reference, it will point to some object always as you have to initialize it when defining it. Do not think reference as a fancy pointer, think of it as an alias name for the object itself. Then this type of confusion will not arise.
A reference can not be NULL. The interface makes you pass a real object into the function.
So there is no need to test for NULL. This is one of the reasons that references were introduced into C++.
Note you can still write a function that takes a pointer. In this situation you still need to test for NULL. If the value is NULL then you return early just like in C. Note: You should not be using exceptions when a pointer is NULL. If a parameter should never be NULL then you create an interface that uses a reference.
A C++ reference is not a pointer nor a Java/C# style reference and cannot be NULL. They behave as if they were an alias to another existing object.
In some cases, if there are bugs in your code, you might get a reference into an already dead or non-existent object, but the best thing you can do is hope that the program dies soon enough to be able to debug what happened and why your program got corrupted.
That is, I have seen code checking for 'null references' doing something like: if ( &reference == 0 ), but the standard is clear that there cannot be null references in a well-formed program. If a reference is bound to a null object the program is ill-formed and should be corrected. If you need optional values, use pointers (or some higher level construct like boost::optional), not references.
As everyone said, references can't be null. That is because, a reference refers to an object. In your code:
// this compiles, but doesn't work, and does this even mean anything?
if (&str == NULL)
you are taking the address of the object str. By definition, str exists, so it has an address. So, it cannot be NULL. So, syntactically, the above is correct, but logically, the if condition is always going to be false.
About your questions: it depends upon what you want to do. Do you want the function to be able to modify the argument? If yes, pass a reference. If not, don't (or pass reference to const). See this C++ FAQ for some good details.
In general, in C++, passing by reference is preferred by most people over passing a pointer. One of the reasons is exactly what you discovered: a reference can't be NULL, thus avoiding you the headache of checking for it in the function.
You can use a special designated object as the null object in case of references as follows:
class SomeClass {
public:
int operator==(SomeClass &object) {
return (this == &object);
}
static SomeClass NullObject;
};
SomeClass SomeClass::NullObject;
void print(SomeClass &val) {
if(val == SomeClass::NullObject)
printf("\nNULL");
else
printf("\nNOT NULL");
}
You should use NULL only with pointers. Your function accepts a reference and they can't be NULL.
Write your function just like you would write it in C.
C++ references naturally can't be null, you don't need the check. The function can only be called by passing a reference to an existing object.
What is the most typical/common way of doing this with an object C++ (that doesn't involve overloading the == operator)?
Is this even the right approach? ie. should I not write functions that take an object as an argument, but rather, write member functions? (But even if so, please answer the original question.)
No, references cannot be null (unless Undefined Behavior has already happened, in which case all bets are already off). Whether you should write a method or non-method depends on other factors.
Between a function that takes a reference to an object, or a function that takes a C-style pointer to an object, are there reasons to choose one over the other?
If you need to represent "no object", then pass a pointer to the function, and let that pointer be NULL:
int silly_sum(int const* pa=0, int const* pb=0, int const* pc=0) {
/* Take up to three ints and return the sum of any supplied values.
Pass null pointers for "not supplied".
This is NOT an example of good code.
*/
if (!pa && (pb || pc)) return silly_sum(pb, pc);
if (!pb && pc) return silly_sum(pa, pc);
if (pc) return silly_sum(pa, pb) + *pc;
if (pa && pb) return *pa + *pb;
if (pa) return *pa;
if (pb) return *pb;
return 0;
}
int main() {
int a = 1, b = 2, c = 3;
cout << silly_sum(&a, &b, &c) << '\n';
cout << silly_sum(&a, &b) << '\n';
cout << silly_sum(&a) << '\n';
cout << silly_sum(0, &b, &c) << '\n';
cout << silly_sum(&a, 0, &c) << '\n';
cout << silly_sum(0, 0, &c) << '\n';
return 0;
}
If "no object" never needs to be represented, then references work fine. In fact, operator overloads are much simpler because they take overloads.
You can use something like boost::optional.