【问题标题】:Nullptr and checking if a pointer points to a valid objectNullptr 并检查指针是否指向有效对象
【发布时间】:2012-07-01 05:00:33
【问题描述】:

在我从未听说过智能指针的几个旧代码项目中,每当我需要检查指针是否仍然指向有效对象时,我总是会做这样的事情......

object * meh = new object;
if(meh) 
    meh->member;

或者当我需要安全地删除对象时,像这样

if(meh)
{
    delete meh;
    meh = 0;
}

好吧,现在我已经了解了在布尔表达式中使用对象和指针可能产生的问题,这两种方法都带有文字数字,很难:。现在,我还了解到了 C++ 中不那么新但非常酷的特性,nullptr 关键字。但现在我很好奇。

我已经完成并修改了大部分代码,例如,在删除我现在编写的对象时

if(meh)
{
    delete meh;
    meh = nullptr;
}

现在我想知道布尔值。当你将一个 int 传递给这样的 if 语句时,

int meh;
if(meh)

然后它会隐式检查零,而无需您编写它。

if(meh == 0) // does the exact same check

现在,C++ 会为指针做同样的事情吗?如果将这样的 char * 传递给 if 语句?

char * meh;
if(meh)

那么它会隐含地把它和nullptr 比较吗?由于我已经像这样编写这些 if 有多久了,此时通过键入 if (object *) 然后调用其成员来检查指针是否有效在这一点上是第二天性。如果这不是功能,为什么不呢?实施起来太难?将通过删除另一种可能会弄乱代码的小方法来解决一些问题。

【问题讨论】:

  • 您确实需要在deleteing 之前检查指针。 deletenullptr 是完全安全的。
  • 在你上一个例子中,你的意思是char * meh = nullptr; if(meh)吗?指针未初始化。
  • new 表达式的结果永远不会为空,而是使用异常。如前所述,删除 null 很好,它什么都不做。此外,通常最好不要将指针值重置为 null。最后一次使用它应该是最后一次不为空,因此访问已删除指针应该被认为是一个错误;将其设置为 null 会隐藏它。
  • “我总是在指针失效后将它设置为零,所以我知道一个非零的指针是有效的”是一个anti-pattern。如果你有两个指向同一个对象的指针会发生什么?将一个设置为零不会影响另一个。
  • @FatalCathasis:会的。但是,如果其他一些代码删除指针的其他一些副本然后取消引用它,则会发生相同的运行时错误。因此,将指针归零既不是必要的,也不是充分的。如果你在不需要的地方使用它,你只是效率低下。但是,如果您在不够用的地方使用它……繁荣。 (当然,这并不意味着你永远不应该这样做。但它很少是适合这项工作的工具,并且在许多严重错误的地方使用。这就是使它成为反模式的原因。)

标签: c++


【解决方案1】:

在 C 中,任何不为 0 的都是真的。所以,你当然可以使用:

if (ptrToObject) 
    ptrToObject->doSomething();

安全地取消引用指针。

C++11 稍微改变了游戏,nullptr_t 是一个类型,nullptr 是一个实例; nullptr_t 的表示是特定于实现的。因此,编译器可以根据需要定义nullptr_t。它只需要确保它可以对将nullptr_t 强制转换为不同类型(其中允许boolean)实施适当的限制,并确保它可以区分nullptr_t 和0 .

因此,只要编译器遵循 C++11 语言规范,nullptr 就会正确且隐式地转换为 boolean false。并且上面的 sn-p 仍然有效。

如果删除引用的对象,则不会发生任何变化。

delete ptrToObject;
assert(ptrToObject);
ptrToObject = nullptr;
assert(!ptrToObject);    

由于我已经像这样编写这些 if 有多久了,此时通过键入 if (object *) 然后调用它的成员来检查指针是否有效是目前的第二天性。

否。请保持正确的对象图(最好使用唯一/智能指针)。正如所指出的,没有办法确定不是nullptr 的指针是否指向有效对象。无论如何,您有责任维护生命周期。这就是指针包装器首先存在的原因。

事实上,因为sharedweak 指针的生命周期是明确定义的,所以它们具有语法糖,可以让您以您希望使用裸指针的方式使用它们,其中有效指针具有值和所有其他人是nullptr

共享

#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);
}

#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);
}

现在,C++ 会为指针做同样的事情吗?如果将这样的 char * 传递给 if 语句?

所以回答这个问题:用 bare 指针,没有。使用 wrapped 指针,

各位,总结一下。

【讨论】:

  • 如果您忘记将指针归零,则会导致运行时错误。但是如果指针与 nullptr 隐式比较,那么无论指针是 0 还是寻址,当对象不存在时,它都会解析为 false。
  • 是的。那么你的问题是什么?
  • @FatalCatharsis 在 C 和 C++ 中,空指针比较等于整数零,非空指针比较不等于整数零——无论指针的按位表示是什么。
  • -_- 他只是解释了我的答案.. 否则他会发布自己的答案。
  • “行为是特定于实现的”是什么意思?它的行为就像标准所说的那样。它的表示和实现取决于实现(但这并不是什么新鲜事。“旧式”空指针的表示也是实现定义的)
【解决方案2】:

无法测试指针是否指向有效对象。如果指针不为空但未指向有效对象,则使用指针会导致未定义的行为。为了避免这种错误,你有责任小心被指向的对象的生命周期;智能指针类可以帮助完成这项任务。

如果meh 是一个原始指针,那么if (meh)if (meh != 0)if (meh != nullptr) 之间没有任何区别。如果指针不为空,它们都会继续进行。

存在从文字 0nullptr 的隐式转换。

【讨论】:

  • 嗯,有办法做到这一点。我见过嵌入self 指针并检查self == this 并在销毁时将self 归零的代码。可能会浪费时间和空间。
  • @user207421 也许你可以用你的想法(和具体的代码)发布一个答案,在我看来你在描述一些不同的东西
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2016-08-19
  • 1970-01-01
  • 1970-01-01
  • 2014-01-01
  • 2011-06-07
  • 2020-03-29
相关资源
最近更新 更多