C ++“智能指针”模板自动转换为裸指针,但不能被明确删除 [英] C++ "smart pointer" template that auto-converts to bare pointer but can't be explicitly deleted

查看:343
本文介绍了C ++“智能指针”模板自动转换为裸指针,但不能被明确删除的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在一个非常大的遗留C ++代码库中工作,应该保持无名。作为一个传统的代码库,它传递原始指针周围的地方。但是我们正在逐步尝试对其进行现代化,因此还有一些智能指针模板。这些智能指针(不同于Boost的scoped_ptr)有一个隐式转换为原始指针,所以你可以把它们之一传入一个例程,它需要一个原始指针,而不必写 .get() 。这样做的一个很大的缺点是,你也可以不小心使用一个 delete 语句,然后你有一个双重免费的bug,这可能是一个真正痛苦的追踪。

I am working in a very large legacy C++ code base which shall remain nameless. Being a legacy code base, it passes raw pointers around all over the place. But we are gradually trying to modernize it and so there are some smart pointer templates as well. These smart pointers (unlike, say, Boost's scoped_ptr) have an implicit conversion to the raw pointer, so that you can pass one of them into a routine that takes a raw pointer without having to write .get(). A big downside of this is that you can also accidentally use one in a delete statement, and then you have a double free bug, which can be a real pain to track down.

有没有办法修改模板,以便它仍然隐式转换为raw指针,但如果在delete语句中使用会导致编译错误?像这样:

Is there a way to modify the template so that it still has the implicit conversion to the raw pointer, but causes a compile error if used in a delete statement? Like this:

#include <my_scoped_ptr>

struct A {};
extern void f(A*);

struct B
{
    scoped_ptr<A> a;

    B();
    ~B();
};

B::B()
    : a(new A)
{
    f(a); // this should compile
}

B::~B()
{
    delete a; // this should NOT compile
}


推荐答案

标准表示


操作数应具有指针类型或具有单个转换函数(12.3.2)的类型类型类型。如果操作数具有类类型,则通过调用上述转换函数将操作数转换为指针类型,并且使用转换后的操作数代替本节其余部分的原始操作数。

The operand shall have a pointer type, or a class type having a single conversion function (12.3.2) to a pointer type. If the operand has a class type, the operand is converted to a pointer type by calling the above-mentioned conversion function, and the converted operand is used in place of the original operand for the remainder of this section.

您可以(ab) - 通过声明一个const版本的转换函数来避免重载解析。在一个合格的编译器,足以使它不再工作与删除

You can (ab)-use the absence of overload resolution by declaring a const version of the conversion function. On a conforming compiler that's enough to make it not work anymore with delete:

struct A {
  operator int*() { return 0; }
  operator int*() const { return 0; }
};

int main() {
  A a;
  int *p = a; // works
  delete a; // doesn't work
}

得到以下结果

[js@HOST2 cpp]$ clang++ main1.cpp
main1.cpp:9:3: error: ambiguous conversion of delete expression of type 'A' to a pointer
  delete a; // doesn't work
  ^      ~
main1.cpp:2:3: note: candidate function            
  operator int*() { return 0; }
  ^
main1.cpp:3:3: note: candidate function             
  operator int*() const { return 0; }
  ^
1 error generated.






在这方面不太符合的编译器EDG / Comeau,GCC),您可以使转换函数成为模板。 delete 不希望使用特殊类型,因此这将工作:


On compilers that are less conforming in that regard (EDG/Comeau, GCC) you can make the conversion function a template. delete does not expect a particular type, so this would work:

template<typename T>
operator T*() { return /* ... */ }

这有一个缺点,你的smartpointer现在可以转换为任何指针类型。虽然实际的转换仍然类型检查,但这不会排除转换前期,而是给更多的编译时错误。不幸的是,SFINAE似乎不可能与C ++ 03 :)中的转换函数。)一种不同的方式是从其他函数返回一个私有嵌套类型指针

However, this has the downside that your smartpointer is now convertible to any pointer-type. Although the actual conversion is still typechecked, but this won't rule out conversions up-front but rather give a compile time error much later. Sadly, SFINAE does not seem to be possible with conversion functions in C++03 :) A different way is to return a private nested type pointer from the other function

struct A {
  operator int*() { return 0; }

private:
  struct nested { };
  operator nested*() { return 0; }
};

现在唯一的问题是转换为 void * ,在这种情况下,两个转换函数同样可行。 @Luther建议的解决方法是从其他转换函数返回一个函数指针类型,它与GCC和Comeau一起工作,并除去 void * 问题与模板解决方案不同,在常规转换路径上没有其他问题。

The only problem now is with a conversion to void*, in which case both conversion functions are equally viable. A work-around suggested by @Luther is to return a function pointer type from the other conversion function, which works with both GCC and Comeau and gets rid of the void* problem while having no other problems on the usual conversion paths, unlike the template solution

struct A {
  operator int*() { return 0; }

private:
  typedef void fty();
  operator fty*() { return 0; }
};

请注意,这些解决方法只适用于不符合的编译器。

Notice that these workarounds are only needed for compilers that are not conforming, though.

这篇关于C ++“智能指针”模板自动转换为裸指针,但不能被明确删除的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆