C++ 析构函数在此代码中隐藏在哪里?
在以下示例中,我很难理解为什么C++ 析构函数在此代码中隐藏在哪里?,c++,c++11,rvalue-reference,move-semantics,move-constructor,C++,C++11,Rvalue Reference,Move Semantics,Move Constructor,在以下示例中,我很难理解为什么Foomove构造函数试图调用~ptr: #include <utility> template <typename T, typename Policy> class ptr { T * m_t; public: ptr() noexcept : m_t(0) {} explicit ptr(T *t) noexcept : m_t(t) {} ptr(const ptr &other) noexc
Foo
move构造函数试图调用~ptr
:
#include <utility>
template <typename T, typename Policy>
class ptr {
T * m_t;
public:
ptr() noexcept : m_t(0) {}
explicit ptr(T *t) noexcept : m_t(t) {}
ptr(const ptr &other) noexcept : m_t(Policy::clone(other.m_t)) {}
ptr(ptr &&other) noexcept : m_t(other.m_t) { other.m_t = 0; }
~ptr() noexcept { Policy::delete_(m_t); }
ptr &operator=(const ptr &other) noexcept
{ ptr copy(other); swap(copy); return *this; }
ptr &operator=(ptr &&other) noexcept
{ std::swap(m_t,other.m_t); return *this; }
void swap(ptr &other) noexcept { std::swap(m_t, other.m_t); }
const T * get() const noexcept { return m_t; }
T * get() noexcept { return m_t; }
};
class FooPolicy;
class FooPrivate;
class Foo {
// some form of pImpl:
typedef ptr<FooPrivate,FooPolicy> DataPtr;
DataPtr d;
public:
// copy semantics: out-of-line
Foo();
Foo(const Foo &other);
Foo &operator=(const Foo &other);
~Foo();
// move semantics: inlined
Foo(Foo &&other) noexcept
: d(std::move(other.d)) {} // l.35 ERR: using FooDeleter in ~ptr required from here
Foo &operator=(Foo &&other) noexcept
{ d.swap(other.d); return *this; }
};
#包括
模板
类ptr{
T*m\T;
公众:
ptr()无例外:m_t(0){}
显式ptr(T*T)noexcept:m_(T){}
ptr(constptr&other)无例外:m_t(Policy::clone(other.m_t)){}
ptr(ptr&&other)无例外:m_t(other.m_t){other.m_t=0;}
~ptr()noexcept{Policy::delete_u(m_t);}
ptr和操作员=(常数ptr和其他)无例外
{ptr副本(其他);交换(副本);返回*this;}
ptr和操作员=(ptr和其他)无例外
{std::swap(m_t,other.m_t);返回*this;}
无效交换(ptr和other)不例外{std::swap(m_t,other.m_t);}
const T*get()const noexcept{return m_T;}
T*get()noexcept{return m_T;}
};
阶级政策;
私人类;
福班{
//某种形式的pImpl:
类型定义ptr数据ptr;
dataptrd;
公众:
//复制语义:不一致
Foo();
Foo(const Foo&其他);
Foo&运算符=(const Foo&其他);
~Foo();
//移动语义:内联
Foo(Foo&其他)不例外
:d(std::move(other.d)){}//l.35错误:从这里开始需要在~ptr中使用FooDeleter
Foo&operator=(Foo&other)无例外
{d.swap(other.d);返回*this;}
};
GCC 4.7:
foo.h: In instantiation of ‘ptr<T, Policy>::~ptr() [with T = FooPrivate; Policy = FooPolicy]’:
foo.h:34:44: required from here
foo.h:11:14: error: incomplete type ‘FooPolicy’ used in nested name specifier
foo.h:在“ptr::~ptr()[with T=FooPrivate;Policy=FooPolicy]”的实例化中:
foo.h:34:44:从这里开始需要
foo.h:11:14:错误:嵌套名称说明符中使用的类型“FooPolicy”不完整
Clang 3.1-pre:
foo.h:11:14: error: incomplete type 'FooPolicy' named in nested name specifier
~ptr() { Policy::delete_(m_t); }
^~~~~~~~
foo.h:34:5: note: in instantiation of member function 'ptr<FooPrivate, FooPolicy>::~ptr' requested here
Foo(Foo &&other) : d(std::move(other.d)) {}
^
foo.h:23:7: note: forward declaration of 'FooPolicy'
class FooPolicy;
^
foo.h:11:20: error: incomplete definition of type 'FooPolicy'
~ptr() { Policy::delete_(m_t); }
~~~~~~^~
2 errors generated.
foo.h:11:14:错误:嵌套名称说明符中命名的类型“FooPolicy”不完整
~ptr(){Policy::delete_u(m_t);}
^~~~~~~~
foo.h:34:5:注意:在这里请求的成员函数'ptr::~ptr'的实例化中
Foo(Foo&&other):d(std::move(other.d)){}
^
foo.h:23:7:注:转发“食品政策”声明
阶级政策;
^
foo.h:11:20:错误:类型“FooPolicy”的定义不完整
~ptr(){Policy::delete_u(m_t);}
~~~~~~^~
产生2个错误。
发生什么事了?我编写move构造函数是为了避免运行复制构造函数和dtor。请注意,这是一个试图隐藏其实现(pimpl习惯用法)的头文件,因此将
foodeler
设为完整类型不是一个选项
编辑:在薄熙来的回答之后,我尽可能地添加了
noexcept
(在上面编辑)。但是错误仍然是一样的。您创建了一个新的Foo
对象,其中包含ptr
成员。如果Foo
构造函数失败,编译器必须为部分构造的Foo
的任何完全构造的成员调用析构函数
但它无法实例化~ptr()
,因此失败
你有一个类似的私人析构函数的例子。这也阻止了您创建这种类型的对象(除非是由朋友或成员函数创建的)。盯着那段代码看了一秒钟,立刻觉得有点头疼,多亏了这个问题,我最近遇到了一个类似的问题,谢天谢地,我没有找到您问题的答案,但正如编译器消息所指出的,
Deleter(m\t);代码>并不是你认为它的意思。它定义了一个未使用的冗余括号变量m\u t
,类型为Deleter
“我编写移动构造函数是为了避免运行复制构造函数和dtor。”这不是编写移动构造函数的好理由。编写移动构造函数的原因要么是因为它是需要移动语义的低级容器类型,要么是因为您使用的Visual Studio不会隐式生成移动构造函数。否则,让编译器来完成它的工作。@hvd:好的,这是一个过于简单化的问题。我现在使用的代码更接近原始代码(这是Qt的QScoped/ExplicitlySharedDataPointer,以防有人想深入了解:我得到了这个错误,例如当Foo
->QPainterPath
)时。@Nicol:根据N3092[class.copy]/10,用户定义的复制构造函数阻止编译器移动构造函数。但是,即使使用Foo(Foo&&)=default
,我也会得到相同的错误。+1,这种情况下的解决方案可能非常简单,只需将所有构造函数和析构函数定义移动到所有类型都已完成的实现文件中。+1;换句话说,您不能内联定义任何Foo
的方法,因为您在头级别隐藏了所有细节。假设更改来自my,您可以使用Foo():d(newfoopprivate){}Foo(Foo const&)=default;Foo(Foo&&)=默认值~Foo()=默认值;Foo&运算符=(Foo)=默认值
作为实现,asptr
正确地处理了所有问题。@Bo:在我尝试将所有ptr
以及Foo
移动ctor和赋值运算符与noexcept
一起抹灰之前,你的回答听起来是合乎逻辑的。AFAIU,这就是noexcept
:允许move-ctors抛出的最初原因。我知道我的不能,那么为什么GCC仍然调用dtor呢?我告诉过它任何东西都不会失败,不是吗?@Marc-我不知道让noexcept
无处不在是否有帮助,或者编译器只是在尝试实例化析构函数(失败)后才看到这一点。