C++ 共享\u ptr析构函数,复制和不完整类型
我有这样一个头文件C++ 共享\u ptr析构函数,复制和不完整类型,c++,c++11,shared-ptr,incomplete-type,C++,C++11,Shared Ptr,Incomplete Type,我有这样一个头文件foo.h(不相关的内容省略): 在getBar()的const重载上(或者实际上是在从该重载实例化的标准库的深处) 我的问题是,这一警告是否可以被安全地忽略 在我看来,在getBar()const中调用了std::shared_ptr的两个成员函数:转换构造函数和析构函数 // converting constructor template <class Y> std::shared_ptr<const Bar>::shared_ptr(std::sh
foo.h
(不相关的内容省略):
在getBar()
的const重载上(或者实际上是在从该重载实例化的标准库的深处)
我的问题是,这一警告是否可以被安全地忽略
在我看来,在getBar()const
中调用了std::shared_ptr
的两个成员函数:转换构造函数和析构函数
// converting constructor
template <class Y>
std::shared_ptr<const Bar>::shared_ptr(std::shared_ptr<Y> &&r)
27.2.2.2§1规定,当销毁的共享指针为空时,没有副作用
我理解为什么我会收到警告-析构函数代码还必须注意在存储指针上调用delete
时的情况,并且该代码确实会删除不完整的类型。但在我看来,在我的情况下永远无法达到它,因此getBar()const
是安全的
我是对的,还是我忽略了一个调用或其他可能导致
getBar()const
实际删除不完整类型的东西?否;这一警告不能被完全忽略。您的代码创建了一个共享的\u ptr对象。shared_ptr构造函数是创建和存储删除器的模板。通过添加代码在头中创建共享的_ptr,您过早地实例化了模板构造函数
shared_ptr使用的deleter技巧允许您在定义类之前声明它们,但是在您首次使用它们之前,它们仍然需要查看完整的类型。你的代码不能保证调用Bar的析构函数。更糟糕的是,今天,它甚至可以工作,但可能是一个定时炸弹,使一个非常难以调试的错误出现在您的代码中
问题与代码中指针的内容无关。只要您有创建共享指针的代码,而该指针看不到Bar的完整定义就足够了
修复很容易。在完成Bar声明之后,只需将该代码放入您的实现文件中
编辑:g++给出的警告适合这种情况,但代码不适合。现在,我将把这个答案留到我有时间调查之前(或者其他人找出g++为什么给出这个警告)。我找不到这个警告的理由。我也不能用clang/libc++复制警告 一般来说,给定一个
shared\u ptr
,如果看不到使用Bar*
的shared\u ptr
的构造,以及可选的删除器,就无法确定~Bar()
是否调用过。没有办法知道shared\u ptr
中存储了什么删除程序,并且给定了shared\u ptr
中存储的一些未知删除程序d
,沿着Bar*
(比如p
)的一侧,d(p)
调用~Bar()
例如,您的条可能没有可访问的析构函数:
class Bar
{
~Bar();
};
您的Foo::getBar()
可以这样实现:
warning C4150: deletion of pointer to incomplete type 'Bar'; no destructor called
std::shared_ptr<Bar>
Foo::getBar()
{
// purposefully leak the Bar because you can't call ~Bar()
return std::shared_ptr<Bar>(new Bar, [](Bar*){});
}
std::共享
Foo::getBar()
{
//由于无法调用~Bar(),所以故意泄漏该条
返回std::shared_ptr(新条,[](条*){});
}
编译器无法在没有看到foo.cpp的情况下知道
在我看来,此警告类似于编译器错误,或者可能是std::shared\u ptr
实现中的错误
你能无视这个警告吗?我不知道。在我看来,您正在处理实现中的一个bug,因此该bug很可能意味着警告是真实的。但是假设是完全一致的实现,我认为在您所展示的代码中不需要将Bar
作为完整类型。const_cast(this)->getBar()“代码>是一个坏把戏-你最好从非常量版本调用常量版本。@ikh我永远无法理解这个参数。在我的例子中,如果非常量版本修改了*此
,你就完蛋了。在你的例子中,如果const版本返回一个指向实际声明的const
的指针,你就完蛋了。两者都有一个失败点,您只需要进行一次额外的强制转换。在const调用non-const时,由类的用户确保不在const对象上调用const版本。在非const调用const时,由类的创建者来确保逻辑有效。不要让你的类成为没有检查你的逻辑的用户的炸弹。@NeilKirk我认为它不会给用户带来负担,它只是要求类的实现者不要在非常量重载中修改*这个。如果它没有修改*这个,那么函数应该是常量。哎呀,现在你有两个常量函数了!我不认为采用shared\u ptr
的构造函数实际上创建了一个deleter——它与参数共享所有权,因此它也必须使用deleter(或缺少deleter)。请注意,使用原始指针的ctor要求指向的类型是完整的,但使用shared\u ptr
的ctor则不是。我说的不是“使用shared\u ptr的构造函数”——而是shared\u ptr的构造函数本身。这是一个模板构造函数——它的工作原理与模板函数类似,因为它将调用参数与模板参数匹配,并基于此派生要使用的类型。一旦模板匹配,它将实例化构造函数。该构造函数创建了删除器,正是该删除器看到了不完整的类型。这正是g++发出此警告的原因。但我只是从问题代码中的另一个共享ptr
构造共享ptr
。链接中的重载(10)是否会创建一个删除器?不要这样认为。。。至少在标准上。是的,我的手机界面很薄,看不清你在做什么。但这是g++针对这种情况给出的警告,因此实现可能仍有待尝试
class Bar
{
~Bar();
};
std::shared_ptr<Bar>
Foo::getBar()
{
// purposefully leak the Bar because you can't call ~Bar()
return std::shared_ptr<Bar>(new Bar, [](Bar*){});
}