检查 C++ 中的指针定义性
Posted
技术标签:
【中文标题】检查 C++ 中的指针定义性【英文标题】:Check for pointer definedness in C++ 【发布时间】:2008-12-19 18:05:05 【问题描述】:如何检查变量,特别是指针,是否在 C++ 中定义?假设我有一堂课:
class MyClass
public:
MyClass();
~MyClass()
delete pointer; // if defined!
initializePointer()
pointer = new OtherClass();
private:
OtherClass* pointer;
;
【问题讨论】:
你能编辑一下标题吗?听起来您想检查是否定义了变量(字面意思)。但看起来您想检查变量是否包含已定义的值。 【参考方案1】:为什么要检查指针值呢?只需将其初始化为空指针值,然后对其调用 delete 即可。空指针上的 delete 什么都不做(标准保证它)。
class MyClass
public:
MyClass():pointer(0)
~MyClass()
delete pointer;
pointer = 0;
initializePointer()
pointer = new OtherClass();
private:
OtherClass* pointer;
;
并且每次调用 delete 时,都应该将指针设置为空指针值。那么你们都很好。
【讨论】:
我通常在编译时将所有警告都视为错误。删除 0 值指针时出现编译错误。 编译器如何知道指针在运行时为零? 托马索,听起来很淘气。我还想知道编译器如何在编译时知道指针在运行时包含的内容。 为什么要在删除后将其设置为 0。在调用对象析构函数后,它不再存在。因此,您不必担心引用它的任何其他内容。 @Greg Rogers:虽然在这里没有帮助,但也没有伤害。在其他情况下,删除发生在代码的另一部分而不是析构函数,将指针设置为 0 将避免通过此变量(而不是通过其他指针)进行双重删除。【参考方案2】:我倾向于在对象构造时将我的指针值初始化为 NULL。这允许检查 NULL 以查看是否定义了指针变量。
【讨论】:
我同意,除了你应该使用 0 而不是 NULL。见research.att.com/~bs/bs_faq2.html#null 或者,在 C++0x 中,你应该使用 nullptr。 我同意,尽管“我倾向于”听起来像是“建议不时呼吸”。【参考方案3】:除了检查0
(NULL
) 之外,一种解决方案是重构您的代码,以便您强制指针始终有效。这并不总是可行的,但在大多数情况下,这是最好的解决方案。
在您的情况下(与大多数其他情况一样),这意味着在构造函数中初始化指针(即在其生命周期开始时)并在其生命周期结束时将其销毁。使变量private
并不允许对其进行直接写访问,以确保它始终保持有效。
这是 C++ 中常用的模式,它有效地将指针对象的对象生命周期限制为类的生命周期。有时,提供某种reset
来删除指针并立即重新初始化它也可能是一个可行的解决方案。如果这是以异常安全的方式编写的,那么您还确保了您的指针永远不会无效。
不要不要创建bool
ean 标志来跟踪指针的有效性。这个解决方案没有优势,也有很多缺点,将指针设置为0
。
【讨论】:
【参考方案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 除非你真的想让对象可复制。
【讨论】:
【参考方案5】:您应该始终在构造函数中将指针初始化为 NULL;这样,您可以检查析构函数是否已初始化。此外,在构造函数的参数列表中这样做更有效:
MyClass::MyClass() : pointer(NULL)
MyClass::~MyClass()
if(pointer != NULL) delete pointer;
同样,如果在程序的生命周期内要多次重新初始化对象,则在删除它时也应该将值设置为 NULL,并在分配它时检查值是否为 null。但是,在析构函数中将值设置为 NULL 不会有任何区别,因为对象显然无论如何都会被销毁。
这样做的好处是(而不是在构造函数中显式地说“指针 = NULL;”)是编译器已经隐式地为你做这样的赋值。进行手动分配会使它发生两次,这通常没什么大不了的,除非您在一个大循环中创建了许多类实例。
【讨论】:
您的代码在 C++ 中毫无意义,因为delete
已经包含 NULL
检查。删除前不要手动检查null!
@Konrad:我不会称之为“毫无意义”,但绝对是“多余的”和“不必要的”【参考方案6】:
你不能,我知道。标准方法是在它不包含有效值时将其设置为 NULL。在任何情况下,将该点周围的指针指向无效内存都是不好的做法。如果您坚持这一点,您可以随时检查 NULL 以查看它是否“已定义”。
【讨论】:
【参考方案7】:另一个尚未提及的附加答案是使用智能指针对象而不是原始指针。根据随后使用指针的方式,std::auto_ptr
、boost::shared_ptr
或许多其他智能指针类可能适用于此处。如果您稍微更改initializePointer()
的工作方式,boost::scoped_ptr
也可能会起作用。
这样,智能指针负责记住它是否有效,并在包含的对象被销毁时删除自己:
class MyClass
public:
MyClass();
~MyClass()
initializePointer()
pointer.reset( new OtherClass());
private:
std::auto_ptr<OtherClass> pointer;
;
【讨论】:
【参考方案8】:真正的answer 是 litb 的,但我只是想补充一下。使用智能指针(在这种情况下 std::auto_ptr 就足够了)可以解决这个问题,并且您不需要记住在析构函数中删除指针。事实上,默认析构函数(由编译器生成)会处理内存资源。
为了使注释更笼统,你的类应该声明赋值运算符和复制构造函数,标记为私有(未定义)或手动定义以避免指针的双重删除。编译器提供的 operator== 和复制构造函数只会复制指针,最终您将进入双重删除。我在这里写这个是因为如果你使用 std::auto_ptr 并在 auto_ptr 中增加了复制语义的陌生性,这也是需要考虑的事情。
【讨论】:
以上是关于检查 C++ 中的指针定义性的主要内容,如果未能解决你的问题,请参考以下文章