使用std :: move()是不成熟的优化吗?
假设我有以下代码:
int main() { std::vector<std::string> strs; std::string var("Hello World"); // Make some modifications to 'var' strs.push_back(std::move(var)); }
我想要指出的部分是std::move()
的用法。 基本上我担心push_back()
调用的副本。 假设我添加的string非常大。 我仍然在学习C ++ 11中的r值引用,所以我不确定编译器如何在没有std::move()
情况下优化拷贝(如果有的话std::move()
。
任何人都可以解释,如果这是一个不成熟的优化(在所有情况下,你想避免复制,一般强制移动)? 如果是这样,我应该期待编译器遵循哪种模式(或者最有可能遵循),这将导致优化和自动移动?
编辑
我想补充一点,我明白自动移动发生在函数返回值上 ,因为NRVO / RVO适用。 我在这里给出的具体例子不适用RVO,所以我不确定。
其他答案太重视技术方面的问题,所以我会尝试给出更一般的答案。
简而言之:不,像在问题中描述的那样使用std :: move这样的“技巧”并不是一个过早的优化。 如果不能使用std::move
,那么也可以使用std::move
,除非代码已经被认为是性能关键的。
避免过早优化的需要有时候被理解为“直到你能certificate是必要的时候才进行优化”,但我更愿意把它理解为:“除非你知道需要解决的问题,否则不要浪费时间解决问题”。
过早优化需要花费精力来优化可能不需要优化的内容,并且通常在这样做时将简单的问题转化为复杂的问题。 从这个angular度来看,我将这个问题本身的长期思考归类为不成熟的优化。
一个相关的例子:在性能关键代码中工作的人们通常会将参数作为常量parameter passing( const std::string&
)。 因为这是他们习惯做的事情,所以即使他们只是使用pass-by-copy( const std::string
,甚至是std::string
),他们也会在代码中使用相同的模式。 这也不是一个过早的优化。
我不确定编译器如何在没有
std::move()
情况下优化拷贝(如果有的话std::move()
。
只有一个非常聪明的编译器可以优化,如果副本可能是昂贵的(例如一个非常长的string),那么最好移动它。
如果没有这个动作,这个代码实际上是一系列的调用:
strlen // count "Hello World" malloc // allocate memory for string var strcpy // copy data into var malloc // re-allocate vector free // deallocate old vector malloc // allocate new string strcpy // copy from var to new string free // destroy var
随着移动它变成:
strlen // count "Hello World" malloc // allocate memory for string var strcpy // copy data into var malloc // re-allocate vector free // deallocate old vector
理论上讲,一个智能编译器可以自动完成这个转换,但是编译器要查看构造函数和析构函数引入的所有抽象层以及vector
成员函数是非常困难的,所以certificate可以转换代码以移除malloc
free
是复杂的。
在std::move
,原始对象(在本例中为var
)必须处于有效状态,但可以保存任何值,例如可能为空。
如果你知道你不打算使用var
而只是将它创build为vector
那么它并不是真正的“过早”优化,因为你正在试图做的事情的意图。
vector
有一个新的方法emplace_back()
,它是相同的东西,但更清晰,并使用前向参数(这里你只是做emplace_back("Hello World")
如果你正在做的是构build它)。 在你的情况,因为你“使用var进行一些修改” emplace_back
不可能是不合适的。
在旧的C++
您可以通过对一个空string执行push_back()
来优化副本,然后交换它。
我不知道为什么每个人都build议你使用emplace_back()
。 emplace_back()
的目的是通过构build对象来避免复制/移动操作。 在这种情况下,你已经构build了这个对象,所以至less有一个复制/移动是不可避免的。 在这种情况下,通过push_back()
使用emplace_back()
没有任何优势。
否则,我同意其他人的观点,认为这不是一个过早的优化,因为移动语义模型比你制作对象更复杂。
是的,如果过早优化,这是不成熟的优化。
让我详细说明一下:
过早优化的定义是,您是否优化了一部分您不认为性能至关重要的代码。 也就是说,过早的优化永远不会被优化的方法所定义,它总是由优化的位置和你所做的知识来定义的。
现在,为了使用std::move()
来优化:
使用std::move()
您可以避免复制构造的繁重工作,如内存分配,释放,复制构build包含的元素,解构包含的元素等等。 但是有一个部分需要重新考虑:容器对象的build造/销毁。
emplace_back()
具有完全避免构造临时对象的优点。 因此,只要使用emplace_back()
来避免临时对象,就可以获得一个小小的胜利。
考虑到代码质量(读取可读性/可维护性): std::move()
有一个缺点,就是给你一个不可用的对象,这可能是一个bug的来源。 emplace_back()
不会发生这种情况。 所以,后者显然更可取。
当然, emplace_back()
不能在允许使用std::move()
所有上下文中使用。 所以,如果这些是性能的关键, std::move()
可能是要走的路。 std::move()
有一些非常有效的用例优化。 不过,您也可能会发现,您可以编写代码,而不需要任何复制/移动/安置构造。 永远不要停止寻找更好的解决scheme,当优化!
最后,使用std::move()
进行优化的有效性完全取决于上下文:无论优化哪个地方,都是很好的优化。