移动构造函数和字符数组参数

Move constructor and char array argument

本文关键字:数组 参数 字符 构造函数 移动      更新时间:2023-10-16
struct Foo
{
    char data[100];
    template<int T>
    Foo(char (&&var)[T])
    {
        data = std::move(var);
        var = 0;
    } 
};
int main()
{ 
    char v[100];
    //..init v
    Foo f( std::move(v) );   //error C2664: 'Foo::Foo<100>(char (&&)[100])' : cannot convert parameter 1 from 'char [100]' to 'char (&&)[100]'
    return 0;
} 

我不明白为什么MSVC对Foo f( std::move(v) )行不满意?(可能这段代码没有意义)

您可以使用来自<algorithm>标头的std::move算法。

auto it = std::move(data, data + T, var);

,检查T不大于100。但是移动char并不比仅仅复制有很多好处。

Foo f( std::move(v) );

在GCC、Clang和Intel中是合法的。然而,Visual Studio抱怨并放弃

error C2664: 'Foo::Foo(const Foo &)' : cannot convert parameter 2 from 'char [100]' to 'char (&&)[100]'
1>          You cannot bind an lvalue to an rvalue reference

这对我来说似乎是个bug。实际上,v是左值,但std::move将其强制转换为右值引用。

由于字符数组是不可移动的,虽然合法,但我不认为通过右值引用来获取它们有多大用处。如果您真的想要编译代码,一个解决方法是使f接受常规(左值)引用,并在调用站点删除std::move。或者更好的是,让f接受一个指向char*的指针(f不需要是模板)。在这种情况下,调用f(v)v[0]的地址(即v的第一个元素)传递给f。这就是所谓的数组到指针的转换,由编译器隐式执行。

然而,正如其他人指出的,

    data = std::move(var);
    var = 0;

对所有编译器都是非法的。datavar是数组(或对数组的引用),数组不可赋值。例如,var = 0;被每个编译器引发的错误如下:

GCC:

error: incompatible types in assignment of 'int' to 'char [100]'

叮当声:

error: array type 'char [100]' is not assignable
英特尔:

error: expression must be a modifiable lvalue
Visual Studio:

error C2440: '=' : cannot convert from 'int' to 'char [100]'