如何为C"类"的C++ 11冒充者实现operator delete?

jot*_*tik -3 c++ porting interface operator-overloading c++11

我正在尝试编写C++ 11冒名顶替者(最好由@jrok称为,因为这些类没有像包装器那样的字段),对于一堆C"类",类似于:

extern "C" {
  struct cfoo;
  cfoo * cfoo_new();
  void cfoo_free(cfoo *);
  int cfoo_bar(cfoo *, int);
} // extern "C" {
class Foo final {
    Foo() = delete;                        // Prevents
    Foo(Foo &&) = delete;                  // construction
    Foo(const Foo &) = delete;             // of this
    Foo & operator=(Foo &&) = delete;      // C++
    Foo & operator=(const Foo &) = delete; // object
public: /* Methods: */
    int bar(int v) noexcept { return cfoo_bar(cPtr(), v); }
    cfoo * cPtr() noexcept { return reinterpret_cast<cfoo *>(this); }
    static Foo * create() {
       cfoo * const f = cfoo_new();
       if (!f) throw std::bad_alloc();
       return reinterpret_cast<Foo *>(f);
    }
    // No member fields! No double dereference! No extra memory!
}; // class Foo {
Run Code Online (Sandbox Code Playgroud)

但是,在C++ 11代码中我也想做类似的事情:

Foo * foo = Foo::create();
foo->bar(42);
delete foo;                                 // (1)
{
  std::unique_ptr<Foo> pFoo(Foo::create()); // no custom deleter!
  pFoo->bar(3);
} // pFoo goes out of scope                 // (2)
Run Code Online (Sandbox Code Playgroud)

使得(1)和(2)将只调用ctest_free(x->cPtr())其中Test * x是传递给指针delete操作.

在C++ 11中实现这个的最恰当/最安全的方法是什么?

编辑:感谢您的答案到目前为止,但请让我们保持这个主题,并避免咆哮编码实践.请回答这个问题,告诉我为什么这不可能实现,或者根据ISO/IEC 14482/2011告诉我我的代码在哪里有未定义的行为.

tcl*_*amb 6

这是未定义的行为,因为您正在调用非(a )Foo的对象上的非静态成员函数.相关标准是§9.3.1/ 2:Foocfoo

如果为非X类型的对象X或派生类型的对象调用类的非静态成员函数X,则行为未定义.

空类的成员函数没有例外.


正如许多其他人已经指出的那样,做正在尝试的事情的最安全和正确的方法是编写包装器类型.例如:

class Foo {
    std::unique_ptr<cfoo, void(*)(cfoo*)> p;
public:
    Foo() : p{cfoo_new(), cfoo_free} { if (!p) throw std::bad_alloc{}; }
    int bar(int i) noexcept { return cfoo_bar(p.get(), i); }
};
Run Code Online (Sandbox Code Playgroud)

将其用法与C接口进行比较:

// Using the C interface
{
    cfoo* foo = cfoo_new();
    if (!foo) throw std::bad_alloc{};
    cfoo_bar(foo, 42);
    cfoo_free(foo);
}

// Using a C++ wrapper
{
    Foo foo;
    foo.bar(42);
}
Run Code Online (Sandbox Code Playgroud)

当使用任何优化编译器时,这将是C接口上的零开销.例如,GCC的汇编输出对于上面的两个块都是相同的.