在 class 主体中声明析构函数且 unique_ptr 作为同一 class 的成员时出现编译器错误
Compiler error when destructor declared in class body with unique_ptr as member of the same class
下面是代码的极简问题:
struct B {
B () = default;
//~B () {}; // error: use of deleted function ‘B& B::operator=(const B&)’
std::unique_ptr<int> m_pB = nullptr;
};
int main ()
{
std::vector<B> vB;
vB.erase(vB.begin());
}
以上代码可以正常编译,除非取消注释析构函数。根据我的要求,我需要明确定义 ~B()
的正文。
如何定义与 unique_ptr
共存于同一个 class 的析构函数体?
注意:尝试定义 = default
版本的复制和移动构造函数无济于事。在我的真实代码中,unique_ptr<int>
是 unique_ptr<forward_declared_class>
。无法在 SO 中找到此问题,但我确信它一定存在。随意标记为欺骗。
您可以声明并实现编译器要求的移动赋值运算符。当然,它会抱怨复制赋值,但是对于您的结构来说,合理的复制似乎是不可能的。
错误消息可能有点误导,因为 std::vector::erase
实现在代码中包含类似 _data[i-1] = _data[i]
的内容,该代码将矢量元素插入已删除项目的位置。所以编译器需要任何赋值运算符,我们为它提供一个移动的。
例如,这工作正常(gcc 4.8.3):
struct B {
B () = default;
B& operator=(B&& op) {
m_pB = std::move(op.m_pB);
return *this;
}
~B () {}; // no more errors.
std::unique_ptr<int> m_pB = nullptr;
};
int main ()
{
std::vector<B> vB;
vB.erase(vB.begin());
}
似乎您的代码需要 B
可复制构造并可复制分配给 std::vector
(至少对于我测试过的 visual c++)。
复制构造函数和复制赋值运算符只能是 = delete
因为 std::unique_ptr
(声明 = default
的实现也应该导致函数被删除),并且通过实现析构函数,您禁用移动构造函数和移动赋值运算符的默认实现。
因此您需要显式声明移动赋值运算符。尝试:
#include <memory>
#include <vector>
struct B {
B () = default;
~B () {}
B& operator=(B&&) = default;
std::unique_ptr<int> m_pB = nullptr;
};
int main ()
{
std::vector<B> vB;
vB.erase(vB.begin());
}
矢量代码是一条红鲱鱼。
当一个classU有一个unique_ptr类型的成员,并且T是前向声明的,析构函数的定义必须在cpp文件中,当U不再是一个不完整的类型。
你应该有 ~U();在 header 和 cpp 文件中有 U::~U(){} 或 U::~U() = default;
下面是代码的极简问题:
struct B {
B () = default;
//~B () {}; // error: use of deleted function ‘B& B::operator=(const B&)’
std::unique_ptr<int> m_pB = nullptr;
};
int main ()
{
std::vector<B> vB;
vB.erase(vB.begin());
}
以上代码可以正常编译,除非取消注释析构函数。根据我的要求,我需要明确定义 ~B()
的正文。
如何定义与 unique_ptr
共存于同一个 class 的析构函数体?
注意:尝试定义 = default
版本的复制和移动构造函数无济于事。在我的真实代码中,unique_ptr<int>
是 unique_ptr<forward_declared_class>
。无法在 SO 中找到此问题,但我确信它一定存在。随意标记为欺骗。
您可以声明并实现编译器要求的移动赋值运算符。当然,它会抱怨复制赋值,但是对于您的结构来说,合理的复制似乎是不可能的。
错误消息可能有点误导,因为 std::vector::erase
实现在代码中包含类似 _data[i-1] = _data[i]
的内容,该代码将矢量元素插入已删除项目的位置。所以编译器需要任何赋值运算符,我们为它提供一个移动的。
例如,这工作正常(gcc 4.8.3):
struct B {
B () = default;
B& operator=(B&& op) {
m_pB = std::move(op.m_pB);
return *this;
}
~B () {}; // no more errors.
std::unique_ptr<int> m_pB = nullptr;
};
int main ()
{
std::vector<B> vB;
vB.erase(vB.begin());
}
似乎您的代码需要 B
可复制构造并可复制分配给 std::vector
(至少对于我测试过的 visual c++)。
复制构造函数和复制赋值运算符只能是 = delete
因为 std::unique_ptr
(声明 = default
的实现也应该导致函数被删除),并且通过实现析构函数,您禁用移动构造函数和移动赋值运算符的默认实现。
因此您需要显式声明移动赋值运算符。尝试:
#include <memory>
#include <vector>
struct B {
B () = default;
~B () {}
B& operator=(B&&) = default;
std::unique_ptr<int> m_pB = nullptr;
};
int main ()
{
std::vector<B> vB;
vB.erase(vB.begin());
}
矢量代码是一条红鲱鱼。
当一个classU有一个unique_ptr类型的成员,并且T是前向声明的,析构函数的定义必须在cpp文件中,当U不再是一个不完整的类型。
你应该有 ~U();在 header 和 cpp 文件中有 U::~U(){} 或 U::~U() = default;