避免在C ++中使用未定义的对象

时间:2019-03-19 09:26:20

标签: c++

如果我使用c ++创建一个类,则即使该类不存在,也可以调用该类的对象的函数。

例如:

班级:

class ExampleClass
{
   private:
       double m_data;

   public:
       void readSomeData(double param)
       {
           m_data = param;
       }
}

使用此类的任何函数:

int main()
{
    ExampleClass* myClass;

    myClass->readSomeData(2.5);
}

这当然不起作用,因为未定义myClass。 为避免这种情况,我检查ExampleClass对象是否为null_ptr

示例:

void readSomeData(double param)
{
    if(this == null_ptr)
        return;

    m_data = param;
}

但是gcc说:

  

'this'指针在定义良好的C ++代码中不能为null;比较可能   被假定总是评估为假。

当然,这只是一个警告,但我认为收到此警告并不好。有没有更好的方法来检查是否定义了类的指针?

3 个答案:

答案 0 :(得分:6)

在类中进行测试是错误的方式,如果您的代码定义正确,则警告是正确的,那么this不能为null,因此测试应在调用成员函数时进行:

int main()
{
    ExampleClass* myClass = nullptr; // always initialize a raw pointer to ensure
                                     // that it does not point to a random address

    // ....    

    if (myClass != nullptr) {
      myClass->readSomeData(2.5);
    }

    return 0;
}

如果指针在代码的特定部分一定不能为null,则应按照CppCoreGuideline: I.12: Declare a pointer that must not be null as not_null

进行操作

Micorosoft提供了一个Guidelines Support Library,其中有一个针对not_null的实现。

或者,如果可能的话,除了std::optional之外不要使用任何指针。

因此代码设置可能如下所示:

#include <gsl/gsl>

struct ExampleClass {
   void readSomeData(double ){}
};

// now it is clear that myClass must not and can not be null within work_with_class
// it still could hold an invalid pointe, but thats another problem
void work_with_class(gsl::not_null<ExampleClass*> myClass) {
  myClass->readSomeData(2.5);
}

int main()
{
    ExampleClass* myClass = nullptr; // always initialize a raw pointer to ensure
                                     // that it does not point to a random address

    // ....

    work_with_class(myClass);

    return 0;
}

答案 1 :(得分:3)

最好的方法是根本不使用指针:

int main()
{
    ExampleClass myClass;
    myClass.readSomeData(2.5);
}

这样一来,就无需进行任何检查,实际上是checking this inside the function is moot

如果需要为空性,请改用std::optional

答案 2 :(得分:1)

要么不要使用Bartek Banachewicz指出的指针,要么正确初始化并检查指针:

int main()
{
    ExampleClass* myClass= 0;

    if (myClass)
       myClass->readSomeData(2.5);

   return 0;
}

当然,您仍然必须在某个时候添加对象的实例化,否则代码是无稽之谈。