2014-09-03 185 views
4

我已經完成了一些託管包裝處理包裝unmanged代碼用於託管,但沒有那麼多,以另一種方式。C++託管到非託管轉換

我正在運行一個實驗,使用託管代碼來查找目錄並將它們返回到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; 
    } 

} 

失敗的 'nativeString1' 和 'nativeString2' 是: 錯誤C2665: 'msclr ::互操作:: marshal_as':無3個重載可以轉換所有的參數類型

'nativeString2'如果您查看錯誤的詳細信息,則會使用const,因爲它在marshal_as的某個簽名中列出。

問題是爲什麼'nativeString1'轉換失敗,但'nativeString'的工作?我的眼睛只是拒絕注意?

在響應線程出現之前:是的,我意識到這不是「最佳」解決方案,它不是平臺獨立的,等等。我試圖專注於這個特定的錯誤。

+0

託管代碼中的Const-correctness非常麻煩,CLR不管它。你的解決方法是一個體面的實用解決方案,額外的變量得到優化,所以沒有什麼可擔心的。 – 2014-09-03 18:26:12

+0

這很有趣!我不知道這是因爲dirs [i]不是一個常量引用,而mStr是。這裏是germane函數的定義:'template <> inline std :: string marshal_as(System :: String^const&_from_obj)'。你可以嘗試創建一個不斷的參考,看看你是否有任何牽引力。 – 2014-09-03 18:47:14

+0

是的,我最初是用「this works」一節中的const定義做的,但發現它不是必需的。字符串^ const mStr = dirs [i]; – user3228938 2014-09-03 20:26:55

回答

3

編譯器不認爲dirs[i]是一個字符串的常量引用(這對我來說也是令人驚訝的)。但是,你可以得到一個臨時的常數參考值,而不使用% operator,這將增加該字符串的dirs[i]引用計數創建一個新的字符串句柄:

// this works as well 
auto nativeString1(marshal_as<std::string>(%*dirs[i])); 
+0

啊! '%'當然是參考指標!我已經使用了幾次,但顯然不足以記住它。我認爲const的部分在這裏是免費的,所以我認爲他們簽名的直接翻譯變成:「對常量字符串的引用」。 – user3228938 2014-09-08 15:54:15

+0

雖然我想知道爲什麼簽名沒有被定義爲「System :: String&const%」,因爲參考定義的'&'在非託管端。 – user3228938 2014-09-08 16:03:06

+0

這是一個巧妙的把戲。我希望他們能解決這個問題。我發現這個問題可以追溯到VS2008。 – Niall 2014-11-12 08:13:26

3

這是由賈斯汀提到的簽名引起的在一個評論,以智慧

template <> inline std::string marshal_as(System::String^ const & _from_obj) 

這是一個非常糟糕的事情要做。這是一個非跟蹤指向Ssytem::String的跟蹤指針。因爲它是一個const引用,所以它可以綁定到一個臨時對象,但因爲它是一個非跟蹤引用,所以它不能綁定到垃圾收集堆內的內存位置,因爲gc堆上的對象可以四處移動。

應該已經能夠通過身份投,它根據C++標準來解決這個問題,創建臨時相同類型的。暫時不在gc堆上,因此所有 都可以。

不幸的是,有一些compiler bugs related to identity casts,因此,你實際上並沒有得到一個臨時的。

賈斯汀轉換爲跟蹤引用並返回到跟蹤指針是另一種創建臨時指針的方法。不幸的是,他的回答中包含了一些關於參考數量的巨大數字。 .NET對象不被引用計數。

最重要的是,沒有理由首先通過const引用傳遞該參數。跟蹤指針很小,很容易複製。這是marshal_as作者的一個樣式錯誤,因爲它是一個錯誤。您可以將頭文件更改爲

template <> inline std::string marshal_as(System::String^ const _from_obj) 

沒有破壞實施。

另一個解決將是使用跟蹤的參考,像

template <> inline std::string marshal_as(System::String^ const % _from_obj) 

但同樣,有沒有點,因爲傳遞的價值是如此便宜。

+0

VS2013.3遇到了這個問題,這個解釋發生了什麼最有意義(錯誤和所有)。 – Niall 2014-11-12 08:30:45

+0

你在.NET中引用計數的好處很多(對不起,它聽起來像是巨無霸!)。 「%'狀態」的文檔「跟蹤引用(%)的行爲與普通C++引用(&)相似,只是當對象分配給跟蹤引用時,對象的引用計數會增加。」我在互操作內部不清楚,但是認爲參考計數是針對非管理方的。如果你可以澄清爲什麼%增加了真棒的裁判計數。 – 2014-11-13 02:35:03

+0

@JustinR .:可能你正在查看C++/CX而不是C++/CLI的文檔嗎? C++/CX訪問了引用計數的WinRT對象,而不是使用基於可達性的世代垃圾收集的.NET對象,而不是參考計數。 – 2014-11-13 02:39:20