4

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

class MyClass {  
public:

    MyClass();

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

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

private:

    OtherClass* pointer;

};
4

8 回答 8

22

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

class MyClass {  
public:

    MyClass():pointer(0) { }

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

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

private:

    OtherClass* pointer;

};

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

于 2008-12-19T18:14:56.540 回答
8

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

于 2008-12-19T18:06:31.517 回答
6

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

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

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

不要创建ean 标志bool跟踪指针的有效性。此解决方案将指针设置为 没有优点,也有许多缺点0

于 2008-12-19T18:12:21.693 回答
4

构造函数的全部意义在于,在它完成后,所有成员变量都被正确定义。在这种情况下,NULL 是一个有效的初始值。

在 NULL 上调用 delete 是明确定义的。

更常见的是,您希望构造函数定义 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<> ,除非您真的想让对象可复制。

于 2008-12-19T18:49:57.653 回答
2

您应该始终在构造函数中将指针初始化为 NULL;这样,您可以检查析构函数是否已初始化。此外,在构造函数的参数列表中这样做更有效,如下所示:

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

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

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

这样做的好处(而不是在构造函数中显式地说“指针 = NULL;”)是编译器已经隐式地为你做这样的赋值。进行手动分配会使它发生两次,这通常没什么大不了的,除非您在一个大循环中创建了许多类实例或其他东西。

于 2008-12-19T18:07:26.727 回答
1

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

于 2008-12-19T18:08:07.833 回答
1

真正的答案是 litb 的答案,但我只是想发表一点评论。使用智能指针(在这种情况下 std::auto_ptr 就足够了)可以解决这个问题,并且您不需要记住在析构函数中删除指针。事实上,默认析构函数(由编译器生成)会处理内存资源。

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

于 2008-12-19T18:47:36.787 回答
1

另一个尚未提及的附加答案是使用智能指针对象而不是原始指针。根据随后使用指针的方式,此处可能适合使用 、 或许多其他智能指针类 std::auto_ptr。如果您稍微改变一下工作方式,也可能会起作用。boost::shared_ptrboost::scoped_ptrinitializePointer()

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

class MyClass {  
public:

    MyClass();

    ~MyClass() {
    }

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

private:

    std::auto_ptr<OtherClass> pointer;

};
于 2008-12-19T18:49:17.513 回答