在C++中,?:运算符比if()... else语句更快?它们在编译代码中有什么区别吗?
为什么三元运算符会阻止MSVC中的返回值优化(RVO)?考虑以下完整的示例程序:
#include <iostream>
struct Example
{
Example(int) {}
Example(Example const &) { std::cout << "copy\n"; }
};
Example FunctionUsingIf(int i)
{
if (i == 1)
return Example(1);
else
return Example(2);
}
Example FunctionUsingTernaryOperator(int i)
{
return (i == 1) ? Example(1) : Example(2);
}
int main()
{
std::cout << "using if:\n";
Example obj1 = FunctionUsingIf(0);
std::cout << "using ternary operator:\n";
Example obj2 = FunctionUsingTernaryOperator(0);
}
Run Code Online (Sandbox Code Playgroud)
使用VC 2013编译如下: cl /nologo /EHsc /Za /W4 /O2 stackoverflow.cpp
输出:
using if:
using ternary operator: …Run Code Online (Sandbox Code Playgroud) 看完这个问题后.我创建了这个小小的测试:
class A{
public:
A(){}
A(const A&){printf("copy\n");}
A(A&&){printf("move\n");}
static A f(){
A a;
return a;}
static A g(){
A a;
return (a);}//could be return *&a; too.
static A h(){
A a;
return true?a:a;}
};
Run Code Online (Sandbox Code Playgroud)
结果是(没有RVO和NRVO):
据我所知,用于决定是否使用复制或移动的规则在12.8.32中描述:
这是指12.8.31的规则:(我只显示相关部分)
按照这些规则,我理解f和h会发生什么:
怎么样?
对我来说,它看起来很像h.我正在返回一个表达式,它不是自动对象的名称,因此我认为它会被复制但是它被移动了.这里发生了什么?
作为一个C++新手,我在理解C++ 11的新Move-Constructor时遇到了问题,我希望有人可以解释我偶然发现的具体情况.我们来看看这个示例代码:
#include <iostream>
using namespace std;
class Model {
public:
int data;
Model(int data) : data(data) { cout << "Constructor" << endl; }
Model(Model&& model) { cout << "Move constructor" << endl; }
~Model() { cout << "Destructor" << endl; }
private:
Model(const Model& model);
const Model& operator=(const Model&);
};
Model createModel(int data) {
return Model(data);
}
int main(void) {
Model model = createModel(1);
cout << model.data << endl;
return 0;
}
Run Code Online (Sandbox Code Playgroud)
所以我创建了一个createModel函数,它应该将模型作为临时右值返回,我想将它分配给左值.我不希望编译器创建Model对象的副本,因此我将复制构造函数定义为私有,并且我对赋值运算符执行相同操作以确保不复制任何数据.执行此操作后,代码正确不再编译,因此我添加了Move构造函数,现在它再次编译.但是当我运行程序时,我得到了这个输出:
Constructor
1 …Run Code Online (Sandbox Code Playgroud) 是否有可能在可能的情况下编写C++代码,我们依赖于返回值优化(RVO),但是否则可以依靠移动语义?例如,由于条件,以下代码无法使用RVO,因此它将结果复制回:
#include <iostream>
struct Foo {
Foo() {
std::cout << "constructor" << std::endl;
}
Foo(Foo && x) {
std::cout << "move" << std::endl;
}
Foo(Foo const & x) {
std::cout << "copy" << std::endl;
}
~Foo() {
std::cout << "destructor" << std::endl;
}
};
Foo f(bool b) {
Foo x;
Foo y;
return b ? x : y;
}
int main() {
Foo x(f(true));
std::cout << "fin" << std::endl;
}
Run Code Online (Sandbox Code Playgroud)
这产生了
constructor
constructor
copy
destructor
destructor
fin
destructor
Run Code Online (Sandbox Code Playgroud)
这是有道理的.现在,我可以通过更改行强制在上面的代码中调用移动构造函数
return …Run Code Online (Sandbox Code Playgroud) 从函数返回对象时,自C ++ 11起,可能会发生以下情况之一,假设已定义了移动构造函数和复制构造函数(另请参见本文结尾处的示例):
前3种情况的建议不要使用显式std::move,因为无论如何执行移动都可能会阻止可能的RVO,例如参见此SO-post。
但是,在4.情况下,显式std::move可以提高性能。但是,由于有些人既不懂标准又不懂汇编程序,所以需要花很多时间来区分情况1-3和4。
因此,我的问题是:有没有一种方法可以统一处理上述所有情况,例如:
这是一些示例,也可以用作测试用例。
所有示例都使用以下helper-class-definition:
struct A{
int x;
A(int x_);
A(const A& a);
A(A&& a);
~A();
};
Run Code Online (Sandbox Code Playgroud)
1.示例: 1.case,RVO执行,现场演示,结果汇编程序:
A callee1(){
A a(0);
return a;
}
Run Code Online (Sandbox Code Playgroud)
2.示例: 1.case,RVO执行,现场演示,结果汇编程序:
A callee2(bool which){
return which? A(0) : A(1);
}
Run Code Online (Sandbox Code Playgroud)
3.示例: 2.case,有资格进行复制删除,未执行RVO,现场演示,结果汇编程序:
A callee3(bool which){ …Run Code Online (Sandbox Code Playgroud) 我正在使用 VS Code 在 Linux 中使用 g++ 进行编译和调试。
需要包括和使用:
#include <string>
#include <iostream>
using namespace std;
Run Code Online (Sandbox Code Playgroud)
这是我的类是可移动的:
class A {
public:
A(const string& strA) : strA(strA) {}
A(const A& a) : A(a.strA) {
}
A(A&& a) : A(a.strA) {
a.strA = "";
}
string strA;
};
Run Code Online (Sandbox Code Playgroud)
返回 A 实例的示例函数:
A RetA() {
A a("a");
A b("bha");
string ex;
cin >> ex;
a.strA += ex;
return ex == "123" ? a : b;
}
Run Code Online (Sandbox Code Playgroud)
这是简单的主要内容:
int main() {
A a(RetA());
return …Run Code Online (Sandbox Code Playgroud)