C++ c++;托管到非托管转换

C++ c++;托管到非托管转换,c++,marshalling,unmanaged,managed,C++,Marshalling,Unmanaged,Managed,我已经做了很多托管包装,处理包装在托管中使用的非托管代码,但没有那么多的是相反的 我正在进行的一个实验涉及使用托管代码查找目录并以std向量返回它们。长话短说,我在处理下面的示例时发现了一个问题 #include "Helper.h" #include <msclr/marshal.h> #include <msclr/marshal_cppstd.h> using namespace msclr::interop; using namespace System;

我已经做了很多托管包装,处理包装在托管中使用的非托管代码,但没有那么多的是相反的

我正在进行的一个实验涉及使用托管代码查找目录并以std向量返回它们。长话短说,我在处理下面的示例时发现了一个问题

#include "Helper.h"

#include <msclr/marshal.h>
#include <msclr/marshal_cppstd.h>

using namespace msclr::interop;

using namespace System;

namespace CLIWrapper {

   std::vector<std::string> Helper::GetDirs(const char* root)
   {
      std::vector<std::string> rval;

      String^ path = gcnew System::String(root);
      array<String^,1>^ dirs = System::IO::Directory::GetDirectories(path);

      for (int i=0;  i < dirs->Length; i++)
      {
         //this fails
         std::string nativeString1(marshal_as<std::string>(dirs[i]));

         //this fails as well
         std::string nativeString2(marshal_as<std::string>((String ^ const)dirs[i]));

         // this works
         String ^mStr = dirs[i];
         std::string nativeString(marshal_as<std::string>(mStr));


         rval.push_back(nativeString);
      }

      return rval;
   }

}
#包括“Helper.h”
#包括
#包括
使用名称空间msclr::interop;
使用名称空间系统;
名称空间CLIWrapper{
std::vector Helper::GetDirs(const char*root)
{
std::向量rval;
字符串^path=gcnew System::字符串(根);
数组^dirs=System::IO::Directory::GetDirectory(路径);
对于(int i=0;iLength;i++)
{
//这失败了
std::string nativeString1(marshal_as(dirs[i]);
//这也失败了
std::string nativeString2(marshal_as((string^const)dirs[i]);
//这很有效
字符串^mStr=dirs[i];
std::字符串nativeString(marshal_as(mStr));
右旋推回(本机驾驶);
}
返回rval;
}
}
“nativeString1”和“nativeString2”的故障为: 错误C2665:'msclr::interop::marshal_as':3个重载都无法转换所有参数类型

“nativeString2”使用常量,因为它列在封送员的一个签名中,就像您查看错误的详细信息一样

问题是为什么“nativeString1”转换失败,而“nativeString”工作?什么是我的眼睛拒绝注意的


在响应线程中出现之前:是的,我意识到这不是最好的解决方案,它不是独立于平台的。等等。我正试图关注这个特定的错误。

< P>编译器不认为<代码> DRI[i] <代码>是对字符串的常量引用(这对我来说也是令人惊讶的)。但是,您可以通过使用获取对值的临时常量引用,而无需创建新的字符串句柄,这将在
dirs[i]
处增加字符串的引用计数:

// this works as well
auto nativeString1(marshal_as<std::string>(%*dirs[i]));
//这同样有效
自动生成1(封送方式(%*dirs[i]);

这是由贾斯汀在评论中提到的签名引起的,也就是说

template <> inline std::string marshal_as(System::String^ const & _from_obj)
在不破坏实现的情况下

另一个修复方法是使用跟踪引用,如

template <> inline std::string marshal_as(System::String^ const % _from_obj)
模板内联标准::字符串封送作为(系统::字符串^const%\u来自\u obj)

但是,同样没有意义,因为传递值非常便宜。

托管代码中的常量正确性非常麻烦,CLR根本不支持它。您的解决方案是一个相当实用的解决方案,额外的变量会得到优化,因此无需担心。这很有趣!我想知道这是否是因为dirs[I]不是常数引用,而mStr是常数引用。以下是相关函数定义:
模板内联std::string封送\u as(System::string^const&\u from \u obj)
。您可以尝试创建一个常量引用,看看是否有吸引力。是的,我最初在“this works”部分使用const定义,但发现它不是必需的。字符串^const mStr=dirs[i];啊!!当然,“%”作为引用指示符!我已经用过好几次了,但显然不太经常记得。我认为const部分在这里是免费的,所以我认为他们签名的直译是:“对常量字符串的引用”。尽管我想知道为什么签名没有定义为“System::string&const%”,因为引用定义的“&”在非托管端。这是一个巧妙的技巧。我希望他们能解决这个问题。我发现有关这个问题的引用可以追溯到VS2008。在VS2013.3中遇到这个问题后,这个关于正在发生的事情的解释是最有意义的(Bug和所有)。您对.NET中的引用计数有很好的理解(很抱歉,这听起来像是胡言乱语!)。“代码> %%/CONTHORE状态的DOC”,“跟踪引用(%)的行为就像普通C++引用(&)),除了当对象被分配给跟踪引用时,对象的引用计数递增。“我不知道互操作内部结构,但假定引用计数是针对非托管侧的。如果您能澄清为什么%会增加ref计数,那将是非常棒的。@JustinR.:您可能正在查看C++/CX而不是C++/CLI的文档?C++/CX访问的是引用计数的WinRT对象,而不是基于可达性而不是引用计数的使用分代垃圾收集的.NET对象。@JustinR.:我刚刚针对您在回答中链接的页面提交了一个文档错误,因为它声称涵盖了C++/CX和C++/CLI,但是对于将C++/CX信息保存在“Windows运行时”标题中,他非常粗心。
template <> inline std::string marshal_as(System::String^ const % _from_obj)