问题描述
我有一个头文件 foo.h 这样(不相关的东西省略):
#pragma once
#include< memory>
class Bar;
struct Foo
{
std :: shared_ptr< Bar> getBar();
std :: shared_ptr< const Bar& getBar()const
{
return const_cast< Foo *>(this) - > getBar
}
};
getBar()的非常量重载是在.cpp文件中实现的,它也可以看到 Bar 的完整定义。
当 foo.h 是从另一个文件(它没有看到 Bar 的定义),VS 2010给了一个警告,如这个:
警告C4150:删除指向不完整类型'Bar'的指针;在 getBar()$ cc的const重载上没有析构函数
$ c>(或者实际上在从那个重载实例化的标准库中的深处)。
我的问题是该警告是否可以安全地忽略。 b
$ b
我看看它,有 std :: shared_ptr< Bar> 的两个成员函数在 getBar()const :转换构造函数和析构函数。
b $ b template< class Y>
std :: shared_ptr< const Bar> :: shared_ptr(std :: shared_ptr< Y>& r)
这用于从 getBar()的返回值初始化 getBar()const 的返回值。 code>。这没有列出任何先决条件(C ++ 11 27.2.2.1§20-22),这将需要 Y ( Bar in my case)to be complete。
// destructor
std :: shared_ptr< const Bar> :: 〜shared_ptr()
27.2.2.2§1声明当被销毁的共享指针为空时,没有副作用。
我明白为什么我得到警告 - 析构函数代码也必须关心 delete 必须在存储的指针上调用,并且这个代码确实会删除一个不完整的类型。但是我看到它,它在我的情况下永远无法达到,所以 getBar()const 是安全的。
我是正确的,还是我忽略了一个调用或者可以使 getBar()const 实际删除一个不完整的类型?
我没有找到警告的理由。我也不能用clang / libc ++复制警告。
一般来说,给定一个 shared_ptr< Bar> 看到 shared_ptr< Bar> 的构造需要一个 Bar * ,并且可以选择一个删除器,知道如果〜Bar()是曾调用。没有办法知道在 shared_ptr< Bar> 中存储什么删除器,并给出一些未知的删除器 d 被存储在 shared_ptr< Bar> 中,位于 Bar * 旁边(例如 p ),不需要 d(p)调用〜Bar()。
例如,您的 Bar 可能没有可访问的析构函数:
class Bar
{
〜Bar();
};
并且您的 Foo :: getBar()可以这样实现:
std :: shared_ptr< Bar>
Foo :: getBar()
{
//有意泄露Bar,因为你不能调用〜Bar()
return std :: shared_ptr< Bar> ,[](Bar *){})
}
编译器没有办法看到foo.cpp。 / p>
这个警告看起来像是一个编译器错误,或者可能是一个执行 std :: shared_ptr 的错误。
您可以忽略警告吗?我不知道。它看起来对我来说,你正在处理一个bug的实现,所以这个bug可能意味着警告是真实的。但是假设一个完全符合的实现,我看到没有要求 Bar 是您显示的代码中的完整类型。
I have a header file foo.h like this (unrelated stuff omitted):
#pragma once #include <memory> class Bar; struct Foo { std::shared_ptr<Bar> getBar(); std::shared_ptr<const Bar> getBar() const { return const_cast<Foo*>(this)->getBar(); } };
The non-const overload of getBar() is implemented in a .cpp file, which also sees the full definition of Bar.
When foo.h is included from another file (which does not see the definition of Bar), VS 2010 is giving me a warning like this:
warning C4150: deletion of pointer to incomplete type 'Bar'; no destructor called
on the const overload of getBar() (or actually on something deep in the standard library instantiated from that overload).
My question is whether that warning can safely be ignored.
The way I look at it, there are two member functions of std::shared_ptr<Bar> being called in getBar() const: the converting constructor and the destructor.
// converting constructor template <class Y> std::shared_ptr<const Bar>::shared_ptr(std::shared_ptr<Y> &&r)
This is used to initialise the return value of getBar() const from the return value of getBar(). This does not list any prerequisites (C++11 27.2.2.1 §20-22) which would require Y (Bar in my case) to be complete.
// destructor std::shared_ptr<const Bar>::~shared_ptr()
27.2.2.2 §1 states that when the shared pointer being destroyed is empty, there are no side effects.
I understand why I'm getting the warning - the destructor code also has to care for the situation when delete has to be called on the stored pointer, and this code would indeed delete an incomplete type. But the way I see it, it can never be reached in my situation, so getBar() const is safe.
Am I correct, or have I overlooked a call or something which could make getBar() const actually delete an incomplete type?
I can find no rationale for the warning. Nor can I replicate the warning with clang/libc++.
In general, given a shared_ptr<Bar>, without seeing the construction of shared_ptr<Bar> that takes a Bar*, and optionally a deleter, there is no way to know for sure if ~Bar() is ever called. There is no way to know what deleter was stored in the shared_ptr<Bar>, and given some unknown deleter d that is stored in the shared_ptr<Bar>, along side of the Bar* (say p), there is no requirement that d(p) call ~Bar().
For example, your Bar may have no accessible destructor:
class Bar { ~Bar(); };
And your Foo::getBar() could be implemented like this:
std::shared_ptr<Bar> Foo::getBar() { // purposefully leak the Bar because you can't call ~Bar() return std::shared_ptr<Bar>(new Bar, [](Bar*){}); }
There is no way for the compiler to know without seeing foo.cpp.
This warning looks like a compiler bug to me, or possibly a bug in the implementation of std::shared_ptr.
Can you ignore the warning? I don't know. It looks to me like you are dealing with a bug in the implementation, and so that bug could well mean that the warning is real. But assuming a fully conforming implementation, I see no requirement for Bar to be a complete type in the code you have shown.
这篇关于shared_ptr析构函数,复制和不完全类型的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!