C#代码调用C ++ / CLI类方法 - 新实例仍然具有旧实例值

时间:2015-06-01 06:18:32

标签: c# memory-leaks c++-cli marshalling destructor

我是一起使用C#和C ++ / CLI代码的新手。在我的C#代码中,我正在创建一个类FooClass的新实例并运行一个方法FooClass:ParseCmdArgs,它接受一个System :: String,转换为一个std :: string,然后推送到一个向量"杆"变量。然后我打印出" bar" ParseCmdArgs函数末尾的内容。但是我得到了下面描述的一些意想不到的输出。

C#代码 - WPF应用程序

private void Button_Click_1(object sender, RoutedEventArgs e)
{
    CLRClass.FooClass foo = new CLRClass.FooClass();

    List<string> args = new List<string>();
    args.Add("1st Run - 1");
    args.Add("1st Run - 2");
    args.Add("1st Run - 3");
    args.Add("1st Run - 4");
    args.Add("1st Run - 5");

    foo.ParseCmdArgs(args.Count, args.ToArray());

    args.Clear();
    args.Add("2nd Run - 1");
    args.Add("2nd Run - 2");
    args.Add("2nd Run - 3");
    args.Add("2nd Run - 4");
    args.Add("2nd Run - 5");

    foo = new CLRClass.FooClass();
    foo.ParseCmdArgs(args.Count, args.ToArray());
}

CLRClass.h

#pragma once
#include <string>
#include <iostream>
#include <msclr\marshal_cppstd.h>

using namespace System;

namespace CLRClass {

  public ref class FooClass
  {
  public:
    void ParseCmdArgs(int, array<System::String^>^);
  };
}

CLRClass.cpp

#include "stdafx.h"

#include "CLRClass.h"

using namespace CLRClass;
using namespace std;

vector<string> bars;

void FooClass::ParseCmdArgs(int argc, array<System::String^> ^argvManaged) {
  string *argv;
  argv = new string[argc];

  for (int j = 0; j < argc; j++) {
    msclr::interop::marshal_context context;
    std::string standardString = context.marshal_as<std::string>(argvManaged[j]);

    argv[j] = standardString;

    bars.push_back(argv[j]);
  }

  cout << "print bars" << endl;
  cout << "-----------" << endl;

  for (int i = 0; i < bars.size(); i++) {
    cout << bars[i] << endl;
  }
}

输出为:

print bars
-----------
1st Run - 1
1st Run - 2
1st Run - 3
1st Run - 4
1st Run - 5
print bars
-----------
1st Run - 1
1st Run - 2
1st Run - 3
1st Run - 4
1st Run - 5
2nd Run - 1
2nd Run - 2
2nd Run - 3
2nd Run - 4
2nd Run - 5

如果您能在这里帮助我,我会有一些疑问:

1)我没想到FooClass的第一个实例分配给&#34; foo&#34;仍然保留&#34;酒吧&#34;的内容变量(在C ++ / CLI代码中)。正如我们从输出中看到的那样,在将一个新的FooClass实例分配给&#34; foo&#34;之后,来自&#34; 1st Run&#34;的旧内容。存储在&#34; new&#34; FooClass实例&#34;&#34;&#34;变量。 1a)有人能看出为什么会这样吗? 1b)我是否需要为FooClass设置析构函数?

2)用一个FooClass实例调用ParseCmdArgs()函数的最佳方法是什么?我想创建一个新的FooClass实例并不理想(不管怎么说都没有,见1)。每次ParseCmdArgs完成时我是否需要执行bars.clear()?

3)我编组/将System :: String转换为std :: string的方式是正确的吗?

4)例如在我当前实现的调用非托管C ++ / CLI类的C#托管代码以及编组的使用中是否存在内存泄漏问题?

感谢您的帮助,如果您需要进一步的详细信息或说明,请与我们联系。

最好的问候

1 个答案:

答案 0 :(得分:1)

您需要将vector<string> bars;作为函数的局部变量。或者至少是你班级的实例领域。

现在它是一个全局变量,只要您将DLL加载到AppDomain中(只需在程序的整个持续时间内放置),它就会保持其值。

这与CLR或托管代码无关。如果从C ++可执行文件调用C ++代码,也会发生同样的情况。