【发布时间】:2014-12-08 02:05:24
【问题描述】:
我正在尝试为一堆 C“类”编写 C++11 冒名顶替者(正如 @jrok 所说,因为这些类没有像包装器那样的字段),类似于:
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 {
但是,在 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)
这样 (1) 和 (2) 只会调用 ctest_free(x->cPtr()),其中 Test * x 是传递给 delete 运算符的指针。
在 C++11 中实现这一点的正确/最安全的方法是什么?
编辑:到目前为止,感谢您的回答,但请让我们保持主题并避免对编码实践进行咆哮。请回答问题,告诉我为什么无法归档,或者根据 ISO/IEC 14482/2011 告诉我我的代码在哪里有未定义的行为。
【问题讨论】:
-
您的班级
Foo应该有一个成员cfoo *,而不是在Foo*和cfoo*之间进行转换。 -
这些是“冒名顶替者”,而不是“包装者”。
-
你到底为什么要在没有任何成员字段的情况下这样做?你认为你会从中获得什么可以想象的优势?
-
@jotik:如果你想让它保持“纯 C++”并且只依赖“由 ISO/IEC 14882 保证”的东西,那么答案是“这是 UB " 就这样结束了!
-
你不能同时拥有它。如果这是一个纯 C++ 问题,那么您的
reinterpret_cast后跟对该对象的任何使用都是完全未定义的行为。如果我们使用成员指针的情况,您的编译器实际上会将 sizeof(Foo) 设置为 sizeof(cfoo*),如果您的Foo是标准布局,则基本上可以保证它只是一个指向cfoo的指针。
标签: c++ c++11 interface operator-overloading porting