Цель повышения:: checked_delete

Я не понимаю цели повышения:: checked_delete. В документации говорится:

Стандарт C++ позволяет, в 5.3.5/5, указателях на неполные типы классов быть удаленным с удалять-выражением. Когда класс имеет нетривиальный деструктор, или определенный для класса оператор удаляет, поведение не определено. Некоторые компиляторы выдают предупреждение, когда неполный тип удален, но к сожалению, не все делают, и программисты иногда игнорируют или отключают предупреждения.

Предоставленные шаблоны функций и шаблоны классов могут использоваться для предотвращения этих проблем, поскольку они требуют полного типа и вызывают ошибку компиляции иначе.

Таким образом, стандарт C++ позволяет Вам удалять неполные типы, который вызывает неопределенное поведение, если тип имеет нетривиальный деструктор. Что? Как неполный тип может иметь какой-либо деструктор вообще? Неполный тип не является просто прототипом?

16
задан Channel72 17 May 2010 в 21:28
поделиться

3 ответа

Наиболее распространенным примером неполного типа является тот, который был только объявлен:

// this file does not include the definition of foo

class foo;

void bad(foo *f)
{
    delete f;  // undefined behavior if there exists foo::~foo
}

В действительности определение foo может выглядеть следующим образом:

class foo
{
public:
    ~foo() { ... };
};

Но если верхний код не «видел» определение класса и просто видит объявление класса, код будет компилироваться.

17
ответ дан 30 November 2019 в 21:53
поделиться

Рассмотрим следующее:

Foo.h:

#ifndef Foo_H
#define Foo_H
#include <boost/scoped_ptr.hpp>
#include <boost/utility.hpp>

class Foo : private boost::noncopyable
{
public:
   Foo();
   ~Foo();

   void do_something_interesting();

private:
   class Impl;  // incomplete type
   boost::scoped_ptr<Impl> impl;
};

#endif

Foo.cpp:

#include "Foo.h"
#include <string>
#include <iostream>

class Foo::Impl
{
public:
    Impl() : name("Foo::Impl")
    {}

    void say_hi()
    { std::cout << name << " says hi!" << std::endl; }

    std::string name;
};

Foo::Foo()
: impl(new Impl)
{}

Foo::~Foo()
{}

void Foo::do_something_interesting()
{ impl->say_hi(); }

Учитывая этот (надуманный) пример, вы не можете ввести ни Foo::Foo, ни Foo::~Foo, потому что тип неполный. Определив оба типа в контексте, где тип Foo::Impl является полным типом, можно безопасно удалить тип. boost::checked_delete делает эту проверку безопасности за вас, и это чисто затраты времени компиляции. Если вы вставите Foo::~Foo или полностью опустете его, вы получите ошибку от boost::checked_delete везде, где вы пытаетесь уничтожить экземпляр Foo.

4
ответ дан 30 November 2019 в 21:53
поделиться

C ++ позволяет использовать delete для переменных, которые в то время являются указателями на неполные типы.

struct S; // incomplete

int main() {
  S* s = NULL;
  delete s; // legal
}

В этот момент компилятор не знает, что такое S на самом деле. Если выясняется, что S имеет нетривиальный деструктор, то компилятору не требуется обнаруживать эту проблему.

С практической точки зрения, вероятно, происходит следующее: когда компилятор встречает инструкцию delete для неполного типа, он выполняет вызов того, что, как он ожидает, будет обычным деструктором по умолчанию, генерируемым компилятором. И если деструктор окажется таким, то все в порядке. Но если окажется, что S имеет нетривиальный деструктор, или если он предоставляет свой собственный специальный метод удаления, то то, что компилятор заполнил ранее, будет неправильным. Однако компилятор позволил предположить, что он правильно скомпилировал инструкцию delete и никогда не оглядывался назад. Когда это предположение неверно, вы получите неопределенное поведение.

Функция Boost гарантирует, что она вызывается только для полных типов, что позволяет избежать неопределенного поведения, которое может возникнуть в неполных типах.

2
ответ дан 30 November 2019 в 21:53
поделиться
Другие вопросы по тегам:

Похожие вопросы: