【问题标题】:Workaround for Making a unique_ptr to a Forward Declared Type将 unique_ptr 设置为前向声明类型的解决方法
【发布时间】:2019-09-18 12:30:56
【问题描述】:

鉴于我有一个forward declared 类型:

class Foo;

我想为这种类型创建一个unique_ptr

unique_ptr<Foo> pFoo;

这在 中运行良好,但我无法使其在 中运行。

C:\Program Files (x86)\Microsoft Visual Studio 11.0\VC\include\memory(1150):错误 C2027:使用未定义类型 Foo (....\src\STETestbed\STETestbed.cpp)
O:\Engine\stetestbed\include\STETestbed\ComponentDirector.h(26) :见Foo
的声明 C:\Program Files (x86)\Microsoft Visual Studio 11.0\VC\include\memory(1149) : 编译类模板成员函数时void std::default_delete&lt;_Ty&gt;::operator ()(_Ty *) throw() const

[
_Ty=Foo
]
C:\Program Files (x86)\Microsoft Visual Studio 11.0\VC\include\memory(1444) : 请参阅正在编译的函数模板实例化void std::default_delete&lt;_Ty&gt;::operator ()(_Ty *) throw() const

[
_Ty=Foo
]
C:\Program Files (x86)\Microsoft Visual Studio 11.0\VC\include\type_traits(743) :请参阅正在编译的类模板实例化std::default_delete&lt;_Ty&gt; 的参考

[
_Ty=Foo
]
C:\Program Files (x86)\Microsoft Visual Studio 11.0\VC\include\memory(1281) :请参阅对正在编译的类模板实例化std::is_empty&lt;_Ty&gt; 的引用

[
_Ty=std::default_delete
]
O:\Engine\stetestbed\include\STETestbed\ComponentDirector.h(63) : 请参阅正在编译的类模板实例化std::unique_ptr&lt;_Ty&gt; 的参考

[
_Ty=Foo
]
C:\Program Files (x86)\Microsoft Visual Studio 11.0\VC\include\memory(1151):错误 C2338:无法删除不完整的类型 (....\src\STETestbed\STETestbed.cpp)
C:\Program Files (x86)\Microsoft Visual Studio 11.0\VC\include\memory(1152):警告 C4150:删除指向不完整类型 Foo 的指针;没有调用析构函数 (....\src\STETestbed\STETestbed.cpp)
O:\Engine\stetestbed\include\STETestbed\ComponentDirector.h(26) : 见Foo的声明

在黑暗时代是否有解决方法,或者我可以不转发声明?

【问题讨论】:

  • pFoo 是成员还是变量?另外,如果 Visual Studio 2012 的标准库不符合 C++11,你可以使用 boost::scoped_ptr 代替吗?
  • @Artyer pFoo 是会员。我没有在这个项目中包含 Boost,而且我想我会在我这样做之前很久就放弃我的前瞻声明。 VS2012 确实支持unique_ptr,但是好像没有完全支持。
  • 包含pFoo的类的析构函数是在header还是.cpp中实现的? (默认/非用户声明算作“在标题中”。)如果是前者,请尝试后者。
  • @MaxLanghof 两个都试过了,对我都没有用:(
  • 您可以尝试提供特定的删除器,它不需要完整的声明类。

标签: visual-studio-2017 visual-studio-2012 c++ visual-studio-2012 smart-pointers unique-ptr forward-declaration


【解决方案1】:

As mentioned by Jarod42 问题似乎是 实现的default_deleter 需要一个完整的类型on 声明。 的最新版本只需要在该点的完整类型括号运算符被调用。

我们可以通过提供一个函子来解决这个问题,该函子提供一个不需要完整类型声明的删除器:

template <typename T>
void custom_deleter(T* param) {
    delete param;
}

要将custom_deleter 用作模板参数,我们需要将其制成仿函数,否则编译器会出错:

错误 C2207:std::_Unique_ptr_base&lt;_Ty,_Dx,_Empty_deleter&gt;::_Mydel:类模板的成员无法获取函数类型

因此,在前向声明 Foo 的标头中,我们需要将 unique_ptr 定义为:

unique_ptr<Foo, function<void(Foo*)>> pFoo

在定义Foo 的实现文件中,我们需要将其分配为:

pFoo = decltype(pFoo)(new Foo, std::function<void(Foo*)>(custom_deleter<Foo>))

【讨论】:

  • struct custom_deleter { template &lt;typename T&gt; void operator() (T* param) const{ delete param; }}; 将允许 std::unique_ptr&lt;Foo, custom_deleter&gt; pFoo; 和简单的 pFoo = decltype(pFoo)(new Foo); (无论如何,您可能应该包含在 custom_make_unique 中)。
  • @Jarod42 哇,谢谢。我尽量避免像瘟疫一样避免newdelete,所以我对它们不太熟悉。但是当我查到这个时,是的,你是完全正确的。 delete 已经为我处理了 nullptr 案例。我已经编辑了。
  • @Jarod42 我也尝试将其包装在 struct custom_deleter 中,但我收到此错误:“警告 C4150:删除指向不完整类型的指针 Foo; 没有调用析构函数”我会问跟进有关如何实施的问题。
  • @Jarod42 我在这里问了后续问题:stackoverflow.com/q/58011898/2642059
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-08-25
  • 2016-01-17
  • 2013-09-25
  • 2012-11-05
  • 1970-01-01
相关资源
最近更新 更多