【问题标题】:Linker error when using unique_ptr in C++/CLI在 C++/CLI 中使用 unique_ptr 时出现链接器错误
【发布时间】:2012-09-19 10:47:48
【问题描述】:

我目前正在将 auto_ptr 的实例转换为 unique_ptr,但我遇到了问题。它在代码的 C++ 部分中运行良好,但是在我的托管 C++/CLI 层中执行此操作时(该软件同时使用 C# 和 C++)我得到链接错误。它编译得很好,但在链接时会中断。 auto_ptr 从来没有任何问题。

我目前正在使用 Visual Studio 2010。有人知道在 C++/CLI 中使用 unique_ptr 有什么问题吗?

我试图在下面的一段代码中总结我的问题,但请注意下面的代码实际上可以编译和工作(我检查了指针的所有权是否正确移动)。编译时我没有收到链接错误,但下面的代码是纯 C++ 而不是 C++/CLI。我只是想举一个关于如何构造代码的最小示例,以便阅读链接器错误更有意义。

#include "stdafx.h"
#include <vector>
#include <memory>
#include <utility>

using namespace std;

namespace Test {

template< class T >
struct LinAlgPoint3 {
  LinAlgPoint3() { x = y = z = 0; };

  union {
    struct {T x,y,z;} ;
    T data_[3];
  };
};

class ContainerClass
{
public:
  void setUniquePtr(
    unique_ptr< vector< LinAlgPoint3< float > > > newUniquePtr1 ,
    unique_ptr< vector< unsigned char > > newUniquePtr2 )
  {
    m_uniquePtr1 = move(newUniquePtr1);
    m_uniquePtr2 = move(newUniquePtr2);
  }

private:
  unique_ptr< vector< LinAlgPoint3< float > > > m_uniquePtr1;
  unique_ptr< vector< unsigned char > > m_uniquePtr2;
};

int main(int argc, char** argv)
{
  auto pos = unique_ptr< vector< LinAlgPoint3< float > > >( new vector< LinAlgPoint3< float > >() );
  auto name = unique_ptr< vector< unsigned char > >(new vector< unsigned char >());
  ContainerClass container;
  container.setUniquePtr(move(pos), move(name));
}

} //namespace Test

链接时出现的错误如下:

error LNK2028: unresolved token (0A0018A5) "private: __cdecl std::unique_ptr<class std::vector<struct LinAlgPoint3<float>,class std::allocator<struct LinAlgPoint3<float> > >,struct std::default_delete<class std::vector<struct LinAlgPoint3<float>,class std::allocator<struct LinAlgPoint3<float> > > > >::unique_ptr<class std::vector<struct LinAlgPoint3<float>,class std::allocator<struct LinAlgPoint3<float> > >,struct std::default_delete<class std::vector<struct LinAlgPoint3<float>,class std::allocator<struct LinAlgPoint3<float> > > > >(class std::unique_ptr<class std::vector<struct LinAlgPoint3<float>,class std::allocator<struct LinAlgPoint3<float> > >,struct std::default_delete<class std::vector<struct LinAlgPoint3<float>,class std::allocator<struct LinAlgPoint3<float> > > > > const &)" (??0?$unique_ptr@V?$vector@U?$LinAlgPoint3@M@Test@@V?$allocator@U?$LinAlgPoint3@M@Test@@@std@@@std@@U?$default_delete@V?$vector@U?$LinAlgPoint3@M@Test@@V?$allocator@U?$LinAlgPoint3@M@Test@@@std@@@std@@@2@@std@@$$FAEAA@AEBV01@@Z) referenced in function "public: static void __clrcall std::unique_ptr<class std::vector<struct LinAlgPoint3<float>,class std::allocator<struct LinAlgPoint3<float> > >,struct std::default_delete<class std::vector<struct LinAlgPoint3<float>,class std::allocator<struct LinAlgPoint3<float> > > > >::<MarshalCopy>(class std::unique_ptr<class std::vector<struct LinAlgPoint3<float>,class std::allocator<struct LinAlgPoint3<float> > >,struct std::default_delete<class std::vector<struct LinAlgPoint3<float>,class std::allocator<struct LinAlgPoint3<float> > > > > *,class std::unique_ptr<class std::vector<struct LinAlgPoint3<float>,class std::allocator<struct LinAlgPoint3<float> > >,struct std::default_delete<class std::vector<struct LinAlgPoint3<float>,class std::allocator<struct LinAlgPoint3<float> > > > > *)" (?<MarshalCopy>@?$unique_ptr@V?$vector@U?$LinAlgPoint3@M@Test@@V?$allocator@U?$LinAlgPoint3@M@Test@@@std@@@std@@U?$default_delete@V?$vector@U?$LinAlgPoint3@M@Test@@V?$allocator@U?$LinAlgPoint3@M@Test@@@std@@@std@@@2@@std@@$$FSMXPEAV12@0@Z)
1>TestClass.obj : error LNK2028: unresolved token (0A0018A6) "private: __cdecl std::unique_ptr<class std::vector<unsigned char,class std::allocator<unsigned char> >,struct std::default_delete<class std::vector<unsigned char,class std::allocator<unsigned char> > > >::unique_ptr<class std::vector<unsigned char,class std::allocator<unsigned char> >,struct std::default_delete<class std::vector<unsigned char,class std::allocator<unsigned char> > > >(class std::unique_ptr<class std::vector<unsigned char,class std::allocator<unsigned char> >,struct std::default_delete<class std::vector<unsigned char,class std::allocator<unsigned char> > > > const &)" (??0?$unique_ptr@V?$vector@EV?$allocator@E@std@@@std@@U?$default_delete@V?$vector@EV?$allocator@E@std@@@std@@@2@@std@@$$FAEAA@AEBV01@@Z) referenced in function "public: static void __clrcall std::unique_ptr<class std::vector<unsigned char,class std::allocator<unsigned char> >,struct std::default_delete<class std::vector<unsigned char,class std::allocator<unsigned char> > > >::<MarshalCopy>(class std::unique_ptr<class std::vector<unsigned char,class std::allocator<unsigned char> >,struct std::default_delete<class std::vector<unsigned char,class std::allocator<unsigned char> > > > *,class std::unique_ptr<class std::vector<unsigned char,class std::allocator<unsigned char> >,struct std::default_delete<class std::vector<unsigned char,class std::allocator<unsigned char> > > > *)" (?<MarshalCopy>@?$unique_ptr@V?$vector@EV?$allocator@E@std@@@std@@U?$default_delete@V?$vector@EV?$allocator@E@std@@@std@@@2@@std@@$$FSMXPEAV12@0@Z)
1>TestClass.obj : error LNK2019: unresolved external symbol "private: __cdecl std::unique_ptr<class std::vector<unsigned char,class std::allocator<unsigned char> >,struct std::default_delete<class std::vector<unsigned char,class std::allocator<unsigned char> > > >::unique_ptr<class std::vector<unsigned char,class std::allocator<unsigned char> >,struct std::default_delete<class std::vector<unsigned char,class std::allocator<unsigned char> > > >(class std::unique_ptr<class std::vector<unsigned char,class std::allocator<unsigned char> >,struct std::default_delete<class std::vector<unsigned char,class std::allocator<unsigned char> > > > const &)" (??0?$unique_ptr@V?$vector@EV?$allocator@E@std@@@std@@U?$default_delete@V?$vector@EV?$allocator@E@std@@@std@@@2@@std@@$$FAEAA@AEBV01@@Z) referenced in function "public: static void __clrcall std::unique_ptr<class std::vector<unsigned char,class std::allocator<unsigned char> >,struct std::default_delete<class std::vector<unsigned char,class std::allocator<unsigned char> > > >::<MarshalCopy>(class std::unique_ptr<class std::vector<unsigned char,class std::allocator<unsigned char> >,struct std::default_delete<class std::vector<unsigned char,class std::allocator<unsigned char> > > > *,class std::unique_ptr<class std::vector<unsigned char,class std::allocator<unsigned char> >,struct std::default_delete<class std::vector<unsigned char,class std::allocator<unsigned char> > > > *)" (?<MarshalCopy>@?$unique_ptr@V?$vector@EV?$allocator@E@std@@@std@@U?$default_delete@V?$vector@EV?$allocator@E@std@@@std@@@2@@std@@$$FSMXPEAV12@0@Z)
1>TestClass.obj : error LNK2019: unresolved external symbol "private: __cdecl std::unique_ptr<class std::vector<struct LinAlgPoint3<float>,class std::allocator<struct LinAlgPoint3<float> > >,struct std::default_delete<class std::vector<struct LinAlgPoint3<float>,class std::allocator<struct LinAlgPoint3<float> > > > >::unique_ptr<class std::vector<struct LinAlgPoint3<float>,class std::allocator<struct LinAlgPoint3<float> > >,struct std::default_delete<class std::vector<struct LinAlgPoint3<float>,class std::allocator<struct LinAlgPoint3<float> > > > >(class std::unique_ptr<class std::vector<struct LinAlgPoint3<float>,class std::allocator<struct LinAlgPoint3<float> > >,struct std::default_delete<class std::vector<struct LinAlgPoint3<float>,class std::allocator<struct LinAlgPoint3<float> > > > > const &)" (??0?$unique_ptr@V?$vector@U?$LinAlgPoint3@M@Test@@V?$allocator@U?$LinAlgPoint3@M@Test@@@std@@@std@@U?$default_delete@V?$vector@U?$LinAlgPoint3@M@Test@@V?$allocator@U?$LinAlgPoint3@M@Test@@@std@@@std@@@2@@std@@$$FAEAA@AEBV01@@Z) referenced in function "public: static void __clrcall std::unique_ptr<class std::vector<struct LinAlgPoint3<float>,class std::allocator<struct LinAlgPoint3<float> > >,struct std::default_delete<class std::vector<struct LinAlgPoint3<float>,class std::allocator<struct LinAlgPoint3<float> > > > >::<MarshalCopy>(class std::unique_ptr<class std::vector<struct LinAlgPoint3<float>,class std::allocator<struct LinAlgPoint3<float> > >,struct std::default_delete<class std::vector<struct LinAlgPoint3<float>,class std::allocator<struct LinAlgPoint3<float> > > > > *,class std::unique_ptr<class std::vector<struct LinAlgPoint3<float>,class std::allocator<struct LinAlgPoint3<float> > >,struct std::default_delete<class std::vector<struct LinAlgPoint3<float>,class std::allocator<struct LinAlgPoint3<float> > > > > *)" (?<MarshalCopy>@?$unique_ptr@V?$vector@U?$LinAlgPoint3@M@Test@@V?$allocator@U?$LinAlgPoint3@M@Test@@@std@@@std@@U?$default_delete@V?$vector@U?$LinAlgPoint3@M@Test@@V?$allocator@U?$LinAlgPoint3@M@Test@@@std@@@std@@@2@@std@@$$FSMXPEAV12@0@Z)
1>D:\Test\Test.dll : fatal error LNK1120: 4 unresolved externals

正如你所看到的(如果你能理解那些令人难以置信的可怕消息)有一些对 MarshalCopy 的引用,这让我担心 C++/CLI 可能还不支持 unique_ptr。

软件的布局是

C# executable -> C++/CLI translation layer (dll) -> C++ dll

因此 C++ dll 使用 unique_ptr 编译良好,但 C++/CLI dll 无法正确链接。

我忘了提一些非常重要的事情:如果我将 unique_ptr 用于更简单的数据类型,例如字符串,它会成功链接。例如:

  auto string1= unique_ptr< string >(new string(20000, 'S'));
  auto string2 = unique_ptr< string >(new string(20000, 'A'));
  string1= std::move(string2);

我还尝试确保使用该变量,以便编译器不会对其进行优化。

编辑:我刚刚测试了添加另一个接受unique_ptr&lt;string&gt; 的外部函数,我尝试发送上面的string1 并且它也中断了!所以问题一定是在生成的 DLL 之间,因为 std::move() 在每个文件/类中都能很好地工作。

【问题讨论】:

  • 当我们只看到错误而不是创建错误的代码时,很难诊断问题。您说此 C++ 代码有效,但您的实际 C++/CLI 代码无效。你能写一些 C++/CLI 代码来解决这个问题吗?
  • 我可以试试...在我的日子里没有从头写过多少 C++/CLI :)
  • 注释掉所有移动调用以获得干净的编译。移动语义是 C++ 编译器实现的 C++11 功能。不是通过 C++/CLI 编译器。你可以发帖到 connect.microsoft.com 来摇动那棵树。
  • 我不认为它会得到一个干净的编译。如果 C++/CLI 编译器没有实现移动语义,unique_ptr 就不可能工作。
  • 然后我得到error C2248: 'std::unique_ptr&lt;_Ty&gt;::unique_ptr' : cannot access private member declared in class 'std::unique_ptr&lt;_Ty&gt;',就像我在上面的小示例中添加对 move() 的调用之前一样。我忘记提及的是,如果我使用 unique_ptr&lt;double&gt; 而不是上面更高级的类型,代码就会编译。不过,我必须再次确认。

标签: c++ visual-studio-2010 c++11 c++-cli unique-ptr


【解决方案1】:

嗯,不知道它现在有多相关,但我在 C++/CLI 上遇到了完全相同的问题,并通过采用 r 值引用而不是值来解决它。我是说: void setUniquePtr(unique_ptr&& a, unique_ptr&& b)

虽然不是最干净的做事方式,但它还是可以编译。

【讨论】:

  • 这应该被标记为答案。为我工作。
【解决方案2】:

阅读那个复杂的错误消息,我认为它抱怨LinAlgPoint3 结构没有复制构造函数。尝试实现复制构造函数,也许还有运算符===,看看能不能解决它。

【讨论】:

  • 感谢您的好建议。你是对的,该类缺少赋值运算符和复制构造函数(它已经有 ==),但添加它们并不能解决问题.. :(
  • 我刚刚在问题的末尾添加了更多信息。
【解决方案3】:

您不能在 DLL 之间传递 C++ 对象并期望它正常工作。

不同模块的内存布局可能不同。几乎可以肯定会使用不同的分配器(这会击落任何拥有内存的 C++ 类型,包括 stringvectorunique_ptr)。

使用指向纯虚拟基类的指针可以帮助解决这个问题。

或者,如果您有 C++ 部分的源代码,请尝试将 C++ 和 C++/CLI 链接到单个 DLL 中,而不是在单独的 DLL 中引用 C++ 代码。

【讨论】:

  • 但是 unique_ptr 需要一个指向析构函数的隐式指针,以便能够根据类型调用正确的析构函数。
  • @AzP:它不只是使用指向析构函数的指针,它专门用于每个删除器。这会导致跨模块边界出现问题。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-09-27
  • 1970-01-01
  • 2020-12-21
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多