Не удаляйте необработанный указатель, который не является владельцем <T>(i.11) - PullRequest
0 голосов
/ 02 ноября 2018

Я пытался экспериментировать с правилами Five / Three / Zero. При компиляции моей программы я получил предупреждение C26401 о том, что я не должен удалять указатель, который мне не принадлежит, и это в строке delete[] pChar_; в функции деструктора.

Я согласен, что у меня возникла проблема, особенно при вызове move ctor, когда я применяю std::swap при вызове исходного объекта.

Так, как я мог исправить эту проблему?

Редактировать : Как предлагается в комментарии, я могу использовать std :: string (Good), но я хочу знать, как исправить проблему, не изменяя типы, скажем, чтобы узнать, что:)

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 голосов
/ 02 ноября 2018

У меня нет под рукой копии VS, которая могла бы воспроизвести ваше предупреждение, но мне кажется, что это предупреждение из Кодекса CPP , в частности I.11: Никогда не передавайте право собственности необработанный указатель (T *) или ссылка (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 (например, она не указывает на строку с нулевым символом в конце), то strlen сначала потерпит неудачу. Поэтому либо произнесите то, что говорит каждая функция std: pChar должен быть действительным указателем на строку с нулем в термах и в противном случае считается UB, либо защитите значение strlen. Если вы охраняете в Стрлене, то достаточно strcpy.

Также вы не проверяете, что Int равно strlen. Они должны быть.

...