从类成员编组管理字符串

时间:2016-12-23 09:48:09

标签: c++-cli

使用marshal_cppstd.hmsclr::interop::marshal_as<>我可以将托管字符串封送到std::string,如下所示:

String^ managed = "test";
std::string unmanaged = marshal_as<std::string>(managed);

现在当managed是我正在编写代码的类的成员时,我在执行此操作时出错:

std::string unmanaged = marshal_as<std::string>(this->managed);

错误说:

  

没有重载函数的实例“marshal_as”匹配参数列表

或编译器错误C2665:

  

'msclr :: interop :: marshal_as':3个重载中没有一个可以转换所有参数类型

当我更改代码以使用辅助变量时,它可以工作:

String^ localManaged = this->managed;
std::string unmanabed = marshal_as<std::string>(localManaged);

这里必须有一些隐式投射,不是吗?为什么会发生这种情况以及如何使简单的单行工作?

1 个答案:

答案 0 :(得分:7)

是的,这是一个非常糟糕的错误消息,并没有帮助您发现真正的问题。模板错误消息通常很难理解。它可以使用一些repro代码:

#include "stdafx.h"
#include <string>
#include <msclr\marshal_cppstd.h>

using namespace System;
using namespace msclr::interop;

ref class Example {
    String^ managed;
public:
    void test() {
        auto bad  = marshal_as<std::string>(this->managed);   // C2665
        auto copy = this->managed;
        auto good = marshal_as<std::string>(copy);
    }
};

您必须查看“输出”窗口以查看编译器正在努力尝试查找marshal_as&lt;&gt;的版本。与参数类型匹配的模板函数。你会看到它考虑两个模板特化,但你想要的那个。这是:

template <class _To_Type, class _From_Type>
inline _To_Type marshal_as(const _From_Type&);

_From_Type&参数是麻烦制造者,请注意它是一个非托管参考,&。与跟踪参考相反,%。或者只是简单地^作为一个引用类型,如System :: String。

很难看出,引用this->managedcopy之间存在巨大差异。在像Example ^这样的对象中,this指针不稳定。它的值可以在此代码运行时更改,在触发垃圾收集时发生。在大多数程序中不太可能,但不是零。当程序中的另一个线程从GC堆分配并触发集合时发生。这种事情每年发生一次。

如果收集发生就像marshal_as&lt;&gt;()正在完成它的工作那将是非常灾难性的。 GC压缩堆后,非托管引用变为无效并指向垃圾。 C ++ / CLI编译器不能让这种情况发生,因此它不会将this->managed&视为_From_Type&的有效替代。从来没有看过它。模板专业化也无法与之匹敌,C2665是不可避免的结果。

copy参数的重大区别在于它的地址始终是稳定的。在未经优化的代码中存储在堆栈帧中,通常在优化器完成后在CPU寄存器中存储。因此copy& _From_Type&的有效替代品,编译器可以毫无困难地生成模板代码。

因此,您找到的解决方法完全有效,并且是执行此操作的最佳方式。如果编译器只是为我们这样做了会很好,但事实并非如此。别名问题也不好,有时您必须将值复制回来。您只需要了解编写C ++ / CLI代码以及混合托管代码和本机代码的结果,您肯定有一天会再次遇到它。