在使用sonarqube检测C++项目代码时,发现一个使用std::move引起的code smell等级的告警,特记录。
- 原文内容:
- Usually, when copying an object, the source object is unchanged, which means that all resources owned by the source objects have to be duplicated during the copy operation. In the case that the source object will no longer be used, this duplication is not efficient. Since C++11, a mechanism named move semantic has been added to detect such cases and replace the expensive copy by a much cheaper move operation that will steal resources.
- The cornerstone of move semantic is the ability to detect during a “copy” if the source object will be reused or not. There are three situations:
- The object is a temporary object, with no name, and if it can’t be named, it can’t be used
- The object is used in some specific places, such as a return statement
- The user explicitly promises to the compiler that he won’t care for the current value of the object any longer. He does so by using the specific cast operation named std::move.
- If the user write std::move in one situation that is already handled by the first two cases, it has two drawbacks:
- It is clumsy, useless code, which make understanding the code more complex
- In some cases, it can decrease performances, because this can deactivate another optimization of the compiler, named copy elision.
- When copy elision occurs, the object is neither copied nor moved (even if the copy/move constructors have side effects), in fact, the two objects are collapsed into only one memory location. When copy elision occurs is compiler-dependent, but is mandatory(强制性的) in the following cases:
- in a return statement if the returned object is a prvalue of the same class type as the function return type
- in the initialization of a variable if the initializer expression is a prvalue of the same class type as the variable type
- This rule reports an issue(即检测出的code smell)when the use of std::move prevents the copy elision from happening.
- Noncompliant Code Example
class A {}; A getA(); A f() { A a = std::move(getA()); // Noncompliant, prevents copy elision vector<A> v; v.push_back(std::move(getA())); // Noncompliant return std::move(a); // Noncompliant, prevents copy elision }
- Compliant Solution
class A {}; void test(A a); A f() { A a = getA(); // Compliant vector<A> v; v.push_back(getA()); // Compliant return a; // Compliant }
-
上面的核心内容就是,c++11标准提供的std::move函数如果使用不当,可能会导致copy elision(即std::move不但不能起到想要的作用,反而会阻碍编译器优化)。有两种方式一定会触发copy elision,其中之一便是:当return语句返回的对象是一个纯右值,且该对象类型与函数返回值类型相同时。
-
相关链接:https://github.com/isocpp/CppCoreGuidelines/blob/036324/CppCoreGuidelines.md#Rf-return-move-local,这个github仓库包含的内容很值得一看,作者是大名鼎鼎的Bjarne Stroustrup与Herb Sutter
-
转载请注明原文链接:https://blog.csdn.net/qq_27727147/article/details/116503414