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告诉我我的代码在哪里有未定义的行为.
这是未定义的行为,因为您正在调用非(a )Foo
的对象上的非静态成员函数.相关标准是§9.3.1/ 2:Foo
cfoo
如果为非
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的汇编输出对于上面的两个块都是相同的.