boost::checked_delete 的目的

发布于 2024-09-01 12:46:35 字数 401 浏览 8 评论 0原文

我不明白 boost::checked_delete 的目的。文档说:

C++ 标准在 5.3.5/5 中允许, 指向不完整类类型的指针 使用删除表达式删除。 当班级有一个不平凡的事情时 析构函数,或特定于类的 运算符删除,行为是 不明确的。一些编译器发出 当类型不完整时发出警告 删除了,但不幸的是,并没有全部删除 这样做,而程序员有时会忽略 或禁用警告。

提供的函数和类 模板可以用来防止这些 问题,因为它们需要完整的 输入,并导致编译错误 否则。

因此,C++ 标准允许您删除不完整的类型,如果该类型具有重要的析构函数,则会导致未定义的行为。什么?不完整的类型怎么可能有析构函数呢?不完整的类型不就是一个原型吗?

I don't understand the purpose of boost::checked_delete. The documentation says:

The C++ Standard allows, in 5.3.5/5,
pointers to incomplete class types to
be deleted with a delete-expression.
When the class has a non-trivial
destructor, or a class-specific
operator delete, the behavior is
undefined. Some compilers issue a
warning when an incomplete type is
deleted, but unfortunately, not all
do, and programmers sometimes ignore
or disable warnings.

The supplied function and class
templates can be used to prevent these
problems, as they require a complete
type, and cause a compilation error
otherwise.

So the C++ standard allows you to delete incomplete types, which causes undefined behavior if the type has a non-trivial destructor. What? How can an incomplete type have any destructor at all? Isn't an incomplete type just a prototype?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

花辞树 2024-09-08 12:46:35

不完整类型的最常见示例是仅声明的类型:

// 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() { ... };
};

但如果顶层代码没有“看到”类定义而只看到类声明,则代码将编译。

The most common example of an incomplete type is one that has only been declared:

// this file does not include the definition of foo

class foo;

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

In reality, the definition of foo may look like this:

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

But if the top code has not 'seen' the class definition and just sees the class declaration, the code will compile.

倦话 2024-09-08 12:46:35

考虑以下内容:

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::FooFoo::~Foo 因为类型是不完整的。通过在类型 Foo::Impl 是完整类型的上下文中定义两者,您可以安全地删除该类型。 boost::checked_delete 会为您执行此安全检查,这纯粹是编译时成本。如果您内联 Foo::~Foo 或完全省略它,则无论您在何处尝试销毁 Foo,您都会从 boost::checked_delete 收到错误代码 > 实例。

Consider the following:

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(); }

Given this (contrived) example, you cannot inline either Foo::Foo or Foo::~Foo because the type is incomplete. By defining both in a context where the type Foo::Impl is a complete type, you can safely delete the type. boost::checked_delete does this safety check for you, and it's purely a compile-time cost. If you either inline Foo::~Foo or omit it entirely, you will get an error from boost::checked_delete wherever you try to destroy a Foo instance.

呆萌少年 2024-09-08 12:46:35

C++ 允许您对当时是指向不完整类型的指针的变量使用delete

struct S; // incomplete

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

编译器此时并不知道 S 到底是什么。如果事实证明 S 有一个不平凡的析构函数,则编译器不需要检测该问题。

实际上,可能发生的情况是,当编译器在不完整类型上遇到删除指令时,它会填充对它期望的类型的普通编译器生成默认析构函数的调用。如果析构函数就是这样,那么一切都很好。但如果事实证明S有一个不平凡的析构函数,或者它提供了自己特殊的删除方法,那么编译器之前填写的内容将会是错误的。然而,编译器允许假设它正确编译了删除指令,并且永远不会回头。当这个假设错误时,你会得到未定义的行为。

Boost 函数确保仅在完整类型上调用它,从而避免在不完整类型上可能发生的未定义行为。

C++ allows you to use delete on variables that at the time are pointers to incomplete types.

struct S; // incomplete

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

The compiler doesn't know at that point what S really is. If it turns out S has a non-trivial destructor, then the compiler is not required to detect that problem.

Practically speaking, what probably happens is that when the compiler encounters the delete instruction on an incomplete type, it fills in a call to what it expects will be the type's ordinary compiler-generate default destructor. And if that's what the destructor turns out to be, then everything's fine. But if it turns out that S has a non-trivial destructor, or if it provides its own special method of deletion, then what the compiler filled in earlier will be wrong. The compiler, however, allowed to assume that it correctly compiled the delete instruction and never look back. When that assumption is wrong, you'll get undefined behavior.

The Boost function ensures that it's called only on complete types, thus avoiding the undefined behavior that may occur on incomplete types.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文