C++ 将托管指针分配给带和不带地址运算符“%”的对象

C++ assigning managed pointers to an object with and without the address operator "%"

我是 C++ 的新手,正在学习如何使用指针,但我 运行 遇到了一些让我对分配指针感到困惑的事情。我有类似于以下的代码:

DateTime^ dt;

...

while(true)
{
    if(!dt)
    {
        //both of these work - compile and the loop will break after a minute
        //dt = DateTime::Now;
        dt = %DateTime::Now;
    }
    else if ((DateTime::Now - *dt).TotalMilliseconds > 60000)
    {
         break;
    }
}

为什么这两个都有效?根据我的理解,dt = %DateTime::Nowdt 指针指向由 DateTime::Now 编辑的对象 return 的引用,这对我来说是自始至终。但是在 dt = DateTime::Now 中发生了什么,因为如果 DateTime::Now 做 return 一个对象那么它不应该给我一个 cannot convert DateTime to DateTime^ 错误吗?似乎为了让第二个工作,DateTime::Now 需要 return DateTime::Now 创建的 DateTime 对象的引用,在这种情况下不应该是第一个一个 dt = %DateTime::Now 给出类似的错误 cannot convert DateTime^^ to DateTime^ or do do smart pointers work differently than normal pointers?

sets the dt pointer to the reference of the object returned by DateTime::Now

那是你出错的地方,DateTime::Now 不是 return 对象。它return是一个,DateTime是一个值类型。引用类型和值类型之间的区别在 C++ 中完全不存在,但在 .NET 中却非常重要。你必须了解它才能编写出高效的代码,这非常高效。

DateTime^ dt;

那是火车跳出轨道的地方,因为 DateTime 是一个值类型,所以你应该声明这个变量 不带 ^ 帽子。遗憾的是,C++/CLI 编译器允许这种语法并实际实现它。该变量存储值的 boxed 副本。故意装箱值是您始终要避免的事情,装箱转换并不便宜。具有值类型的 .NET 的全部意义在于使程序更快。

但是,是的,正如您发现的那样,C++/CLI 编译器知道如何装箱值而无需您明确说明。虽然应该避免,但有时值被装箱并不罕见。例如,无法调用虚拟 ToString() 方法。所以你不必使用 %。装箱创造了所有值类型都派生自 System::Object.

的错觉

if(!dt)

我必须假设这就是您真正想要的,检测到一个变量是 "not initialized"。在那个 .NET 中有一个更有效的模式,您可以改用 Nullable<> 类型。像这样:

Nullable<DateTime> dt;
while (true) {
    if (!dt.HasValue) {
        dt = DateTime::Now;
    }
    else if ((DateTime::Now - dt.Value).TotalMilliseconds > 60000) {
        break;
    }
}

可以通过 多种 方式进行改进,您可以通过以下方式避免停火版本:

System::Threading::Thread::Sleep(60000);