Я не понимаю цели повышения:: checked_delete. В документации говорится:
Стандарт C++ позволяет, в 5.3.5/5, указателях на неполные типы классов быть удаленным с удалять-выражением. Когда класс имеет нетривиальный деструктор, или определенный для класса оператор удаляет, поведение не определено. Некоторые компиляторы выдают предупреждение, когда неполный тип удален, но к сожалению, не все делают, и программисты иногда игнорируют или отключают предупреждения.
Предоставленные шаблоны функций и шаблоны классов могут использоваться для предотвращения этих проблем, поскольку они требуют полного типа и вызывают ошибку компиляции иначе.
Таким образом, стандарт C++ позволяет Вам удалять неполные типы, который вызывает неопределенное поведение, если тип имеет нетривиальный деструктор. Что? Как неполный тип может иметь какой-либо деструктор вообще? Неполный тип не является просто прототипом?
Наиболее распространенным примером неполного типа является тот, который был только объявлен:
// 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() { ... };
};
Но если верхний код не «видел» определение класса и просто видит объявление класса, код будет компилироваться.
Рассмотрим следующее:
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
.
C ++ позволяет использовать delete
для переменных, которые в то время являются указателями на неполные типы.
struct S; // incomplete
int main() {
S* s = NULL;
delete s; // legal
}
В этот момент компилятор не знает, что такое S
на самом деле. Если выясняется, что S
имеет нетривиальный деструктор, то компилятору не требуется обнаруживать эту проблему.
С практической точки зрения, вероятно, происходит следующее: когда компилятор встречает инструкцию delete
для неполного типа, он выполняет вызов того, что, как он ожидает, будет обычным деструктором по умолчанию, генерируемым компилятором. И если деструктор окажется таким, то все в порядке. Но если окажется, что S
имеет нетривиальный деструктор, или если он предоставляет свой собственный специальный метод удаления, то то, что компилятор заполнил ранее, будет неправильным. Однако компилятор позволил предположить, что он правильно скомпилировал инструкцию delete
и никогда не оглядывался назад. Когда это предположение неверно, вы получите неопределенное поведение.
Функция Boost гарантирует, что она вызывается только для полных типов, что позволяет избежать неопределенного поведения, которое может возникнуть в неполных типах.