在具有删除复制构造函数的 class 元素的数组初始化中需要但未使用的移动构造函数
Move constructor needed, but not used, in array initialization with elements of class with deleted copy constructor
对于冗长的标题,我深表歉意,但我无法简洁地表达这个问题。
我有一个带有 delete
d 复制构造函数和复制赋值运算符的 class。当我尝试使用 class 的实例初始化数组时,除非我提供移动构造函数,否则会出现编译器错误。但是,实际上并没有调用提供的移动构造函数。
这是一个说明问题的 MWE。
#include <cstdio>
#include <string>
class A
{
public:
explicit A(std::string s) : s_(s) { puts("constructor"); }
A() = delete;
~A() = default;
A(const A &other) = delete;
A &operator=(const A &other) = delete;
// A(A &&other) : s_(std::move(other.s_)) { puts("move constructor"); }
void print_s() { printf("%s\n", s_.c_str()); }
private:
std::string s_;
};
int main()
{
A arr[]{A{"some"}, A{"string"}};
for (auto &a : arr) {
a.print_s();
}
}
移动构造函数如图所示被注释掉后,出现错误:
> g++ file.cc -g -std=c++11 -o file && ./file
file.cc: In function ‘int main()’:
file.cc:22:32: error: use of deleted function ‘A::A(const A&)’
22 | A arr[]{A{"some"}, A{"string"}};
| ^
file.cc:10:2: note: declared here
10 | A(const A &other) = delete;
| ^
file.cc:22:32: error: use of deleted function ‘A::A(const A&)’
22 | A arr[]{A{"some"}, A{"string"}};
| ^
file.cc:10:2: note: declared here
10 | A(const A &other) = delete;
| ^
如果我取消注释移动构造函数,我会得到输出
constructor
constructor
some
string
所以,移动构造函数实际上并没有被调用。
为什么需要移动构造函数?我是否在某处犯了错误(例如,一个执行不佳的移动构造函数)?
有
A arr[]{A{"some"}, A{"string"}};
您正在创建两个临时 A
对象,然后将它们 copying/moving 放入数组中。现在,编译器可以优化此 copy/move,但 class 仍然需要 copyable/moveable 才能实现。当您注释掉移动构造函数时,class 不再可复制或移动,因此您会遇到编译器错误。
需要注意的是,这在 C++17 中发生了变化,其 。对于无法复制或移动的类型,代码将在 C++17 及更高版本中编译。
如果你改变
explicit A(std::string s) : s_(s) { puts("constructor"); }
到
A(std::string s) : s_(s) { puts("constructor"); }
那么你的 main
函数可以变成
int main()
{
A arr[]{{"some"}, {"string"}};
for (auto &a : arr) {
a.print_s();
}
}
即使您无法复制或移动 A
。
也能编译
对于冗长的标题,我深表歉意,但我无法简洁地表达这个问题。
我有一个带有 delete
d 复制构造函数和复制赋值运算符的 class。当我尝试使用 class 的实例初始化数组时,除非我提供移动构造函数,否则会出现编译器错误。但是,实际上并没有调用提供的移动构造函数。
这是一个说明问题的 MWE。
#include <cstdio>
#include <string>
class A
{
public:
explicit A(std::string s) : s_(s) { puts("constructor"); }
A() = delete;
~A() = default;
A(const A &other) = delete;
A &operator=(const A &other) = delete;
// A(A &&other) : s_(std::move(other.s_)) { puts("move constructor"); }
void print_s() { printf("%s\n", s_.c_str()); }
private:
std::string s_;
};
int main()
{
A arr[]{A{"some"}, A{"string"}};
for (auto &a : arr) {
a.print_s();
}
}
移动构造函数如图所示被注释掉后,出现错误:
> g++ file.cc -g -std=c++11 -o file && ./file
file.cc: In function ‘int main()’:
file.cc:22:32: error: use of deleted function ‘A::A(const A&)’
22 | A arr[]{A{"some"}, A{"string"}};
| ^
file.cc:10:2: note: declared here
10 | A(const A &other) = delete;
| ^
file.cc:22:32: error: use of deleted function ‘A::A(const A&)’
22 | A arr[]{A{"some"}, A{"string"}};
| ^
file.cc:10:2: note: declared here
10 | A(const A &other) = delete;
| ^
如果我取消注释移动构造函数,我会得到输出
constructor
constructor
some
string
所以,移动构造函数实际上并没有被调用。
为什么需要移动构造函数?我是否在某处犯了错误(例如,一个执行不佳的移动构造函数)?
有
A arr[]{A{"some"}, A{"string"}};
您正在创建两个临时 A
对象,然后将它们 copying/moving 放入数组中。现在,编译器可以优化此 copy/move,但 class 仍然需要 copyable/moveable 才能实现。当您注释掉移动构造函数时,class 不再可复制或移动,因此您会遇到编译器错误。
需要注意的是,这在 C++17 中发生了变化,其
如果你改变
explicit A(std::string s) : s_(s) { puts("constructor"); }
到
A(std::string s) : s_(s) { puts("constructor"); }
那么你的 main
函数可以变成
int main()
{
A arr[]{{"some"}, {"string"}};
for (auto &a : arr) {
a.print_s();
}
}
即使您无法复制或移动 A
。