C++/CLI 传递 String ^ 作为跟踪参考无法按预期工作
C++/CLI passing a String ^ as a tracking reference doesn't work as expected
我在 VS 2010 中使用 C++/CLI。感谢 this 的回答,我了解到在 C++/CLI 中你可以像这样通过引用传递对象
voin func(String ^ %string){
//modify string
}
我想做的是将一些参数传递给 GetInput
形式的构造函数。然后将它们从用户输入修改为这个表单。当表单关闭时,调用者表单将获得在 GetInput
表单中输入的值。
它对 List<double>
有效,但对 String^
无效。这是代码:
public ref class GetInput : public System::Windows::Forms::Form
{
public:
List<double>^ _data;
String ^ _string_data;
GetInput(List<double>^ %data, String ^ %string_data){
_data = data;
_string_data = string_data;
//this code is here just for the sake of an example,
//it's actually in one of the methods
_data->Add(0.5);
_string_data = "15";
}
//void buttonClickHandler where i actually want to modify data and string_data
}
List _data
被修改,以及传递的 data
,但是当我修改 String _string_data
时,原始 string_data
保持不变。但是,如果我修改 string_data
本身 - 它工作正常。此外,跟踪引用不能是 class 的成员,因此将 _string_data 声明为引用无效。
明显的解决方法是传递由一个 String^
组成的 List^
,但我想知道为什么它不起作用以及是否有办法使我的方法起作用.来自原生 C++,这似乎是一种非常简单的方法——只需将指针传递给数据。但是 C++/ClI 跟踪引用有些不同。
我还读到 "A tracking reference is updated when the object moves on the garbage-collected heap." (source)。有人可以澄清这是什么意思吗?我怀疑这包含我的问题的答案,但我不太明白:)
更新:
基本上我想在 C++/CLI 中这样做:
class GetInput {
string * s;
GetInput(string * caller_wants_this_modified){
s = caller_wants_this_modified;
}
void method_to_modify_the_string(){
(*s) = "New string value"; // modifies the string passed by the caller
}
}
我需要将传递给构造函数的指针保存为 class 成员,然后在其中一个成员函数中更改此指针指向的数据。
But C++/ClI tracking references are something different
认为 "tracking reference" 有一些神奇的东西可能是让你在这里遇到麻烦的原因。 C++/CLI 语言和文档强调了这一点,它是为本地 C++ 程序员编写的。 实际上并没有什么不同。
它只是一个指针。
它的行为也完全像一个指针,无论是在处理器上还是在语法上。关于它的唯一 "special" 是垃圾收集器可以找回它。必要的,这样它才能完成它的工作。 C++/CLI 设计者选择使用 ^
而不是 *
因为它们确实有限制。普通的,例如,您不能使其成为非托管 class 的成员。 GC 无法知道它在内存中的位置,因此无法完成它的工作。
你的问题很简单,你有两个指针。 _string_data
和 string_data
。请注意,您选择的名称并不能完全帮助您正确选择。您更新了 _string_data 指针,赋值后它现在指向“15”。但是不是你通过引用传递的指针,它仍然指向原始字符串。因此,当然不会将任何更改传播回调用方。不知道是什么意思,但很随意:
_string_data = "15";
string_data = _string_data;
现在调用者还将看到其引用更新为“15”。现在两个指针都指向同一个对象。
请注意,您对 List<>
参数的理解也有误。您没有更新data
指针。您也不需要,您没有创建新的 List 对象。您的代码只修改了对象,而不是指向对象的指针。所以通过引用传递它是完全没有必要的。
还有一个细节与这个问题有关。请注意,您通过调用其 Add() 方法修改了 List<> 对象。但是你不能对 String 做同样的事情。它是immutable,none它的方法和属性允许你修改它的内容。这给了它非常理想的行为,字符串始终是线程安全的,并且始终可以安全地作为参数传递给方法。确保它永远不会被修改。它的行为就像一个值。
或者换句话说,您必须通过引用传递字符串指针以将更改传播回调用者。
请注意 List<> 不是一成不变的,您的 Add() 调用彻底改变了对象。使用您的 class 的客户端程序员不太可能期望发生这种情况。 C++ 中的 const 关键字是表达差异的一种很好的方式。然而,它在 C++/CLI 中的表现并不好,其他 .NET 语言对它一无所知。您可以在声明中使用 const,它不能在运行时强制执行。
我在 VS 2010 中使用 C++/CLI。感谢 this 的回答,我了解到在 C++/CLI 中你可以像这样通过引用传递对象
voin func(String ^ %string){
//modify string
}
我想做的是将一些参数传递给 GetInput
形式的构造函数。然后将它们从用户输入修改为这个表单。当表单关闭时,调用者表单将获得在 GetInput
表单中输入的值。
它对 List<double>
有效,但对 String^
无效。这是代码:
public ref class GetInput : public System::Windows::Forms::Form
{
public:
List<double>^ _data;
String ^ _string_data;
GetInput(List<double>^ %data, String ^ %string_data){
_data = data;
_string_data = string_data;
//this code is here just for the sake of an example,
//it's actually in one of the methods
_data->Add(0.5);
_string_data = "15";
}
//void buttonClickHandler where i actually want to modify data and string_data
}
List _data
被修改,以及传递的 data
,但是当我修改 String _string_data
时,原始 string_data
保持不变。但是,如果我修改 string_data
本身 - 它工作正常。此外,跟踪引用不能是 class 的成员,因此将 _string_data 声明为引用无效。
明显的解决方法是传递由一个 String^
组成的 List^
,但我想知道为什么它不起作用以及是否有办法使我的方法起作用.来自原生 C++,这似乎是一种非常简单的方法——只需将指针传递给数据。但是 C++/ClI 跟踪引用有些不同。
我还读到 "A tracking reference is updated when the object moves on the garbage-collected heap." (source)。有人可以澄清这是什么意思吗?我怀疑这包含我的问题的答案,但我不太明白:)
更新: 基本上我想在 C++/CLI 中这样做:
class GetInput {
string * s;
GetInput(string * caller_wants_this_modified){
s = caller_wants_this_modified;
}
void method_to_modify_the_string(){
(*s) = "New string value"; // modifies the string passed by the caller
}
}
我需要将传递给构造函数的指针保存为 class 成员,然后在其中一个成员函数中更改此指针指向的数据。
But C++/ClI tracking references are something different
认为 "tracking reference" 有一些神奇的东西可能是让你在这里遇到麻烦的原因。 C++/CLI 语言和文档强调了这一点,它是为本地 C++ 程序员编写的。 实际上并没有什么不同。
它只是一个指针。
它的行为也完全像一个指针,无论是在处理器上还是在语法上。关于它的唯一 "special" 是垃圾收集器可以找回它。必要的,这样它才能完成它的工作。 C++/CLI 设计者选择使用 ^
而不是 *
因为它们确实有限制。普通的,例如,您不能使其成为非托管 class 的成员。 GC 无法知道它在内存中的位置,因此无法完成它的工作。
你的问题很简单,你有两个指针。 _string_data
和 string_data
。请注意,您选择的名称并不能完全帮助您正确选择。您更新了 _string_data 指针,赋值后它现在指向“15”。但是不是你通过引用传递的指针,它仍然指向原始字符串。因此,当然不会将任何更改传播回调用方。不知道是什么意思,但很随意:
_string_data = "15";
string_data = _string_data;
现在调用者还将看到其引用更新为“15”。现在两个指针都指向同一个对象。
请注意,您对 List<>
参数的理解也有误。您没有更新data
指针。您也不需要,您没有创建新的 List 对象。您的代码只修改了对象,而不是指向对象的指针。所以通过引用传递它是完全没有必要的。
还有一个细节与这个问题有关。请注意,您通过调用其 Add() 方法修改了 List<> 对象。但是你不能对 String 做同样的事情。它是immutable,none它的方法和属性允许你修改它的内容。这给了它非常理想的行为,字符串始终是线程安全的,并且始终可以安全地作为参数传递给方法。确保它永远不会被修改。它的行为就像一个值。
或者换句话说,您必须通过引用传递字符串指针以将更改传播回调用者。
请注意 List<> 不是一成不变的,您的 Add() 调用彻底改变了对象。使用您的 class 的客户端程序员不太可能期望发生这种情况。 C++ 中的 const 关键字是表达差异的一种很好的方式。然而,它在 C++/CLI 中的表现并不好,其他 .NET 语言对它一无所知。您可以在声明中使用 const,它不能在运行时强制执行。