检查C ++中的指针定义

时间:2008-12-19 18:05:05

标签: c++ pointers

如何检查C ++中是否定义了变量,特别是指针?假设我有一个班级:

class MyClass {  
public:

    MyClass();

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

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

private:

    OtherClass* pointer;

};

8 个答案:

答案 0 :(得分:22)

为什么要担心检查指针值?只需将其初始化为空指针值,然后只需在其上调用delete即可。删除空指针什么都不做(标准保证它)。

class MyClass {  
public:

    MyClass():pointer(0) { }

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

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

private:

    OtherClass* pointer;

};

每次调用delete时,都应该将指针设置为空指针值。那你一切都很好。

答案 1 :(得分:8)

我倾向于在对象构造时将指针值初始化为NULL。这允许检查NULL以查看是否定义了指针变量。

答案 2 :(得分:6)

除了检查0NULL)之外,还有一个解决方案是重构代码,以便强制指针始终有效。这并非总是可行,但在大多数情况下,这是最好的解决方案。

在您的情况下(与大多数其他情况一样),这意味着在构造函数中初始化指针(即,一旦其生命周期开始)并在其生命周期结束时销毁它。创建变量private并且不允许对它进行直接写访问以确保它始终保持有效。

这是C ++中经常使用的模式,它有效地将指针对象的对象生命周期限制为类的生命周期。有时候,提供某种删除指针并立即重新初始化它的reset也可能是一种可行的解决方案。如果这是以异常安全的方式编写的,那么您还确保指针永远不会无效。

创建bool ean标志以跟踪指针的有效性。将指针设置为0

时,此解决方案没有任何优势和许多缺点

答案 3 :(得分:4)

构造函数的重点是在完成所有成员变量之后才能正确定义。在这种情况下,NULL是有效的初始值。

明确定义了对NULL的调用。

更常见的是你希望构造函数定义RAW指针的值。另外,因为你的对象包含一个RAW指针并且显然拥有它(它正在删除它,这意味着所有权)你还必须确保覆盖编译器生成的Copy Constructor和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;
};

或者,您可以使用其中一个标准智能指针。可能是std :: auto_ptr<>除非你真的想让对象可以复制。

答案 4 :(得分:2)

您应该始终在构造函数中将指针初始化为NULL;这样你可以检查析构函数是否已经初始化。此外,在构造函数的参数列表中执行此操作更有效:

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

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

同样,在删除它时,还应该将值设置为NULL,并在分配时将值检查为null,如果在程序的生命周期内将多次重新初始化对象。但是,在析构函数中将值设置为NULL不会产生任何差别,因为对象显然会被销毁。

这样做的好处(而不是在构造函数中显式地说“pointer = NULL;”)是编译器已经隐式为你做了这样的赋值。做一个手动分配会使它发生两次,这通常不是什么大问题,除非你在一个大循环中做了很多类的实例。

答案 5 :(得分:1)

你不能,我知道AFAIK。标准方法是在它不包含有效值时将其设置为NULL。在任何情况下,将指针都指向无效内存是不好的做法。如果您坚持这一点,您可以随时检查NULL以查看它是否“已定义”。

答案 6 :(得分:1)

真正的answer是轻微的,但我只想发表评论。使用智能指针(在本例中为std :: auto_ptr就足够了)可以解决问题,并且具有以下优点:您不需要记住在析构函数中删除指针。实际上,默认析构函数(由编译器生成)将处理内存资源。

使注释更加通用,您应该声明赋值运算符和复制构造函数标记为私有(并且未定义)或手动定义以避免指针的双重删除。编译器提供的运算符==和复制构造函数将只复制指针,最终你将进入双删除。我在这里写这个,因为如果你使用std :: auto_ptr,并在auto_ptr中添加了复制语义的奇怪性,那么这也是需要考虑的事情。

答案 7 :(得分:1)

另一个没有提到的答案是使用智能指针对象而不是原始指针。根据指针随后的使用方式,std::auto_ptrboost::shared_ptr或许多其他智能指针类可能适合此处。如果您更改boost::scoped_ptr的工作方式,initializePointer()也可能有用。

这样智能指针就会记住它是否有效,并在包含对象被销毁时自行删除:

class MyClass {  
public:

    MyClass();

    ~MyClass() {
    }

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

private:

    std::auto_ptr<OtherClass> pointer;

};