views:

3287

answers:

8

How do I check if a variable, specifically a pointer, is defined in C++? Suppose I have a class:

class MyClass {  
public:

    MyClass();

    ~MyClass() {
        delete pointer; // if defined!
    }

    initializePointer() {
        pointer = new OtherClass();
    }

private:

    OtherClass* pointer;

};
+6  A: 

I tend to initialize my pointer values to NULL on object construction. This allows a check against NULL to see if the pointer variable is defined.

Gabriel Isenberg
I agree except that you should use 0 not NULL. see http://www.research.att.com/~bs/bs_faq2.html#null
Douglas Leeder
Or, in C++0x, you should use nullptr.
Max Lybbert
I agree, though "I tend to" makes it sound like "it's advisable to breathe from time to time".
peterchen
+2  A: 

You should always initialize your pointers to NULL in your constructor; that way you can check in the destructor if it's been initialized. Also, it's more efficient to do it in the constructor's argument list like so:

MyClass::MyClass() : pointer(NULL)
{
}

MyClass::~MyClass()
{
    if(pointer != NULL) { delete pointer; }
}

Likewise, you should also set the value to NULL when you delete it and check the value against null when allocating it, if the object is going to be re-initialized many times during the lifespan of your program. However, setting the value to NULL in the destructor won't make any difference, since the object is obviously going to be destroyed anyways.

The advantage of doing it this way (instead of saying "pointer = NULL;" explicitly in the constructor) is that the compiler is already implicitly doing an assignment like this for you. Doing a manual assignment makes it happen twice, which normally isn't a big deal except if you are making many instances of your class in a big loop or something.

Nik Reiman
Your code is meaningless in C++, since `delete` already includes a `NULL` check. Do not check for null manually before deleting!
Konrad Rudolph
@Konrad: I wouldn't call it "meaningless", but definitely "redundant" and "unnecessary"
James Curran
+1  A: 

You can't, AFAIK I know. A standard method is to set it to NULL when it contains no valid value. Leaving pointers around that point to invalid memory is bad practice under any circumstances. If you stick to this, you can always check for NULL to see if it's "defined" or not.

Vilx-
+5  A: 

In addition to checking for 0 (NULL), one solution would be to refactor your code so you force the pointer to always be valid. This is not always possible, but in most cases, it's the best solution.

In your case (as in most other cases), this means initializing the pointer in the constructor (i.e. as soon as its lifetime starts) and destroy it at the end of its lifetime. Make the variable private and don't allow direct write access to it to ensure that it will always stay valid.

This is an often used pattern in C++ and it effectively bounds the object lifetime of the pointee to the lifetime of your class. Sometimes, it might also be a viable solution to provide some kind of reset that deletes the pointer and immediately re-initializes it. If this is written in an exception-safe way, you've also ensured that your pointer will never be invalid.

Do not create a boolean flag to keep track of your pointer's validity. This solution has no advantage, and many disadvantages, to setting the pointer to 0.

Konrad Rudolph
+15  A: 

Why worry about checking for the pointers value? Just initialize it to a null pointer value and then just call delete on it. delete on a null pointer does nothing (the standard guarantees it).

class MyClass {  
public:

    MyClass():pointer(0) { }

    ~MyClass() {
        delete pointer;
        pointer = 0;
    }

    initializePointer() {
        pointer = new OtherClass();
    }

private:

    OtherClass* pointer;

};

And everytime you call delete on it, you should set the pointer to a null pointer value. Then you are all fine.

Johannes Schaub - litb
I usually compile with all warnings treated as errors. I got compilation errors for deleting 0-valued pointers.
tunnuz
How does the compiler know that a pointer will be zero at run-time?
James Curran
Tommaso, that sounds naughty. i would also like to know how the compiler can know at compile-time what the pointer contains at runtime.
Johannes Schaub - litb
why bother setting it to 0 after you delete it. After an objects destructor is called it doesn't exists anymore. Therefore you don't have to worry about anything else referencing it.
Greg Rogers
@Greg Rogers: while it does not help here, it does not hurt either. In other situations, where instead of the destructor the delete takes place in another part of the code, setting the pointer to 0 will avoid a double delete through this variable (not through other pointers).
David Rodríguez - dribeas
Concur with Greg
Martin York
i didn't want to sound foolish. saying "you should set it to null after deleting it" and then not doing it isn't nice stuff :) also we could add members later that could try using it and testing for non-null in their destructors. so i do "always make it null" instead of "only make null when needed".
Johannes Schaub - litb
I'll retry, maybe my errors in compiling were caused by other constructs.
tunnuz
@dribeas - I wish I could give you +1 for that comment.
Marcin
+1  A: 

The real answer is that of litb, but I just wanted to make a side comment. Using smart pointers (in this case std::auto_ptr suffices) takes care of the problem and has the advantage that you will not need to remember to delete the pointer in the destructor. In fact default destructor (generated by the compiler) will take care of memory resources.

Making the comment even more general, you class should declare assignment operator and copy constructor marked as private (and not defined) or manually defined to avoid double deletes of the pointer. Compiler provided operator== and copy constructor will just copy the pointer and eventually you will get into a double delete. I write this here since that is also something to take into account if you use std::auto_ptr with the added strangeness of the copy semantics in auto_ptr.

David Rodríguez - dribeas
Yep, don't use raw pointers for resource control. Ever.
Jimmy J
+1  A: 

An additional answer that no else has mentioned yet is to use a smart pointer object instead of a raw pointer. Depending on how the pointer is subsequently used, std::auto_ptr, boost::shared_ptr, or a number of other smart pointer classes might be appropriate here. boost::scoped_ptr might also work if you change how initializePointer() works a little bit.

That way the smart pointer takes care of remembering whether it's valid or not and deleting itself when the containing object is destroyed:

class MyClass {  
public:

    MyClass();

    ~MyClass() {
    }

    initializePointer() {
        pointer.reset( new OtherClass());
    }

private:

    std::auto_ptr<OtherClass> pointer;

};
Michael Burr
Hard to believe people are even considering raw pointers in 2009...
Jimmy J
+2  A: 

The whole point of the constructor is that after it has completed all member variables are correctly defined. In this case NULL is a valid initial value.

Calling delete on NULL is well defined.

More normally though you would expect the constructor to define the value of the RAW pointer. Also because your object contains a RAW pointer and obviously owns it (it is deleting it, this implies ownership) you MUST also make sure you override the compiler generated versions of Copy Constructor and Assignment Operator.

class MyClass
{  
    public:
        MyClass()
            :pointer(NULL)  // valid value.
        {}
        ~MyClass()
        {
            delete pointer; // This is fine.
        }

        void initializePointer() // Missing return type
        {
            pointer = new OtherClass();
        }

    private:
        MyClass(MyClass const& copy);           // If you don't define these 
        MyClass& operator=(MyClass const& copy);// two the compiler generated ones
                                                // will do nasty things with owned
                                                // RAW pointers.

        OtherClass* pointer;
};

Alternatively you can use one of the standard smart pointers. Probably std::auto_ptr<> unless you really want to make the object copyable.

Martin York