为什么 vector.push_back(System::Byte) 在 VC++ 14.29 (C++/CLI) 中不再编译

Why does vector.push_back(System::Byte) not compile any more in VC++ 14.29 (C++/CLI)

我有以下用于编译和工作正常的代码:

std::vector<unsigned char> marshal_as(cli::array<System::Byte>^ const& from) 
{
    std::vector<unsigned char> result;
    result.reserve(from->Length);
    for (int i = 0; i < from->Length; i++)
    {
        result.push_back(from[i]);
    }
    return result;
}

将 VisualStudio 更新到版本 16.10 后 - 将 C++ 编译器更新到版本 14.29 - 代码产生错误:

error C2664: 'void std::vector<unsigned char,std::allocator<_Ty>>::push_back(const _Ty &)': cannot convert argument 1 from 'unsigned char' to 'const _Ty &' with [ _Ty=unsigned char ]

message : An object from the gc heap (element of a managed array) cannot be converted to a native reference

message : see declaration of 'std::vector<unsigned char,std::allocator<_Ty>>::push_back' with [ _Ty=unsigned char ]

将循环体中的代码更改为

    unsigned char b = from[i];
    result.push_back(b);

解决了问题。

我想了解这个错误的原因。这在某种程度上与 C++ 20 标准引起的变化有关吗?

Is this somehow related to a change due to the C++ 20 standard?

没有。虽然 std::vector<>::push() 在 C++20 中发生了微妙的变化,但这并不是对这里发生的事情产生实质性影响的变化,这个问题肯定是特定于 clr 的。

I would like to understand the cause of this error.

这几乎可以肯定(见下文)是您的代码中始终存在的错误,但以前版本的 C++/CLI 编译器未报告。

考虑以下函数:

void foo(const int& v) {
  int* ptr = &v;
  // store ptr somewhere, long-term.
}

很明显,调用 foo() 并引用 gc-backed int 将导致灾难。然而,这正是 result.push_back(from[i]); 所做的。

您的代码“有效”,因为 push_back() 碰巧对其参数没有执行任何操作,这导致了问题。但是,编译器不应该知道

N.B. 我几乎可以肯定地说是因为我花了大量时间来追踪 cli::array<T>::operator[](std::size_t) const 的调用签名。以前 return a T 和现在 returns const T%.

也不是不可能