不要删除不是owner <t>的原始指针(i.11)

时间:2018-11-02 18:13:06

标签: c++ move-semantics

我正在尝试试验5/3/0的规则。编译程序时,我收到警告C26401,说我必须删除自己不拥有的指针,并且不要在析构函数的行delete[] pChar_;中删除它。

我同意,在调用move ctor时,在调用源对象时应用std::swap时,我特别会在此发布问题。

那么我该如何解决这个问题?

编辑 :如评论中所建议,我可以使用std :: string(好),但我想知道如何在不修改类型的情况下解决此问题让我们说学习:)

using namespace std;

struct A
{

  A();
  A(int Int, const char* pChar);

  A(const A& rhs);
  A& operator=(A rhs);

  A(A&& rhs);

  ~A();

  void swap(A& rhs);
  int Int_ = 0;
  char *pChar_ = nullptr;
};

A::~A()
{
    std::cout << "----DTOR----" << std::endl;

    if (pChar_ != nullptr)
    {
        delete[] pChar_;
        pChar_ = nullptr;
    }
}

A::A(int Int, const char* pChar) :
     Int_(Int), pChar_(new char[strlen(pChar) + 1])
{
    strncpy_s(pChar_, strlen(pChar) + 1, pChar, _TRUNCATE);
}

A::A(const A& rhs) : A(rhs.Int_, rhs.pChar_) {}

A& A::operator=(A rhs)
{   
    swap(rhs);
    return *this;
}

A::A(A&& rhs)
{
    swap(rhs);
}

void A::swap(A& rhs)    
{
    std::swap(this->Int_, rhs.Int_);
    std::swap(this->pChar_, rhs.pChar_);
}

int main()
{
    A v1{ 1, "Hello" }; 
    {
        A v3{ std::move(v1) };
    }
}

1 个答案:

答案 0 :(得分:1)

我没有可方便地重现您的警告的VS副本,但在我看来,警告来自CPP Code Guidelines,特别是I.11: Never transfer ownership by a raw pointer (T*) or reference (T&)

  

执法

     
      
  • (简单)警告删除不是owner<T>的原始指针。建议使用标准库资源句柄或使用owner<T>
  •   

因此解决方案是使用gsl::owner<char *> pChar_ = nullptr;。请注意,gsl::owner仅仅是为了帮助代码读者(人类或工具)提供注释,并且不会神奇地使您的代码安全。

据我所见,您的代码看起来还可以。


我遇到的一个问题是ctor:

A(int Int, const char* pChar) :
    Int_(Int), pChar_(new char[strlen(pChar) + 1])
{
    strncpy_s(pChar_, strlen(pChar) + 1, pChar, _TRUNCATE);
}

这是伪装成安全代码的不安全代码。 strncpy_s带给您安全感。但是实际上,它绝对不会在代码中执行任何操作(出于安全考虑)。因为如果pChar出现问题(例如,它不指向以null结尾的字符串),那么strlen将首先失败。因此,要么说出每个std函数所说的话:pChar应该是指向以空值结尾的字符串的有效指针,否则应计为UB,或者保护在strlen处。一旦警惕了,strcpy就足够了。

您也不必检查Int是否等于strlen。他们应该是。