检查有关移动未初始化变量和使用移动变量的信息

时间:2013-01-19 22:28:10

标签: c++ c++11 g++ warnings move

在调试会话之后,我意识到下一个示例代码编译没有警告(g ++ - 4.7.2 -Wextra和-Wall)

char *p;
char *q = std::move(p);
*p = 'p';
*q = 'q';

我有点震惊,我有三个问题。

1-我错过了关于移动语义的内容,并且有理由在这种情况下不发出警告,或者gcc的检查不够好?

2-下一个代码是否应该发出警告?

char c = 'c';
char *p = &c;
char *q = std::move(p);
*p = 'p';

据我所知,std::move(p) p可以保留任何值,因此移动p时就像一个未初始化的变量。

3-其他工具/编译器可以检查这些错误吗?

2 个答案:

答案 0 :(得分:1)

  

1-我遗漏了一些关于移动语义的东西,并且有一个原因是在这种情况下没有抛出警告,或者gcc检查不够好?

代码错误,所以警告会很好。 G ++不够聪明,无法“看到”对std::move的调用。通过引用函数传递未初始化的变量是有效的(该函数可能初始化变量),因此调用std::move本身不会触发警告。因为q被赋值,所以它似乎被初始化为编译器。

如果我启用优化以便G ++内联调用std::move,那么我从G ++ 4.7中收到错误:

f.cc: In function ‘int main()’:
f.cc:6:9: warning: ‘p’ is used uninitialized in this function [-Wuninitialized]

这是因为对std::move的调用不再对编译器“不透明”,当它分析内联代码时,它可以看到p永远不会被赋值。编译器仍然不够智能,看不到q永远不会得到好的值,std::move内的强制转换可能会混淆编译器。

  

2-下一个代码应该发出警告吗?

没有。 std::move不会更改指针等基本类型,因此p的值不会更改。标准库表示对象在移动后处于“有效但未指定”状态,因为标准通常不定义移动构造函数或移动赋值运算符的确切行为,但对于基本类型(如{{1 }和int没有移动构造函数。 char*只是将对象转换为右值,它不会改变它,并且用值初始化std::move(p)也不会改变它 - 它只是复制值。

  

3-其他工具/编译器可以检查这些错误吗?

即使进行了优化,Clang和ICC也没有就第一个例子发出警告。

请注意,尽管警告非常有用,但编译器并不完美,因此无法警告所有不安全的代码。当不安全的代码没有得到警告时,你不应该完全惊讶(可能会打开编译器的错误报告来请求它被改进) - 这并不意味着代码没问题。没有警告并不意味着没有错误。

答案 1 :(得分:0)

指针的移动构造函数是微不足道的,这意味着它与其复制构造函数相同:复制值。因此,就C ++ 11而言,这将复制指针。在你的第一种情况下,它正在复制未初始化的指针。

现在,如果那些是std::unique_ptr个对象,那么代码就不正确了。但是没有理由期望编译器对它发出警告,因为编译器无法某些移动的对象无法调用operator*

通常,标准库声明已移动的对象保持有效但未定义的状态。例如,这是完全合法的:

std::vector<int> src = ...;
std::vector<int> dest = std::move(src);
src.assign(...);

std::unique_ptr的不同之处在于它确切地指定了移动对象离开它的状态。但是编译器不能假设任何类型。它不能假定对象处于无效状态,其中任何特定函数调用必须失败。