在 if 块中调用函数时如何使用复制省略
How to use copy elision when function is called in if block
在以下代码段中,由于复制省略
,A
没有移动也没有复制发生
struct A;
A function1();
A function2();
int main(int argc, char**) {
if (argc > 3) {
A a = function1();
} else {
A a = function2();
}
return 0;
}
这很好,但是 a
在 if 块之外无法访问。在外部声明 a
时,会发生移动
struct A;
A function1();
A function2();
int main(int argc, char**) {
A a;
if (argc > 3) {
a = function1();
} else {
a = function2();
}
return 0;
}
当它应该发生在调用站点的 if 块中到 if 范围之外的变量时,从复制省略中获益的推荐模式是什么?
在这种特殊情况下,您可以使用三元条件:
A a = argc>3 ? function1() : function2();
在更复杂的情况下,您可能需要保存条件并进行多项检查,例如
const bool cond = argc>3;
A a = cond ? function1() : function2();
A b = cond ? function3() : function4();
一般来说placement new在arbitrary[=29]中使用纯右值(“强制复制省略”,不是复制省略) =] 上下文(例如,带有语句或重用变量)。然后,您还有责任手动调用 析构函数 ;安全和干净的方法是写一个助手 class:
template<class T>
struct box {
char buf[sizeof(T)]; // real code should handle alignment
T *p{}; // will point to buf
void reset() {
if(p) p->~T();
p=nullptr;
}
~box() {reset();}
};
void f() {
box<A> a;
if(…) a.p=new (a.buf) A(function1());
else a.p=new (a.buf) A(function2());
// use *a.p
}
当然,box
只是对 std::optional
的重新实现,并暴露了胆量。不幸的是,您必须在外部 box::p
分配 ,但是将 new
包装在函数中当然会 materialize从任何函数返回的 A
的临时值。 (让 box::p
成为一个指针而不仅仅是一个标志可以避免使用 std::launder
来处理 lifetime 问题。)
立即调用的 Lambda 表达式 (IILE) 可以在这种情况和更复杂的情况下节省时间:
A a = [&] {
if (…) {
return function1();
} else {
return function2();
}
}();
在以下代码段中,由于复制省略
,A
没有移动也没有复制发生
struct A;
A function1();
A function2();
int main(int argc, char**) {
if (argc > 3) {
A a = function1();
} else {
A a = function2();
}
return 0;
}
这很好,但是 a
在 if 块之外无法访问。在外部声明 a
时,会发生移动
struct A;
A function1();
A function2();
int main(int argc, char**) {
A a;
if (argc > 3) {
a = function1();
} else {
a = function2();
}
return 0;
}
当它应该发生在调用站点的 if 块中到 if 范围之外的变量时,从复制省略中获益的推荐模式是什么?
在这种特殊情况下,您可以使用三元条件:
A a = argc>3 ? function1() : function2();
在更复杂的情况下,您可能需要保存条件并进行多项检查,例如
const bool cond = argc>3;
A a = cond ? function1() : function2();
A b = cond ? function3() : function4();
一般来说placement new在arbitrary[=29]中使用纯右值(“强制复制省略”,不是复制省略) =] 上下文(例如,带有语句或重用变量)。然后,您还有责任手动调用 析构函数 ;安全和干净的方法是写一个助手 class:
template<class T>
struct box {
char buf[sizeof(T)]; // real code should handle alignment
T *p{}; // will point to buf
void reset() {
if(p) p->~T();
p=nullptr;
}
~box() {reset();}
};
void f() {
box<A> a;
if(…) a.p=new (a.buf) A(function1());
else a.p=new (a.buf) A(function2());
// use *a.p
}
当然,box
只是对 std::optional
的重新实现,并暴露了胆量。不幸的是,您必须在外部 box::p
分配 ,但是将 new
包装在函数中当然会 materialize从任何函数返回的 A
的临时值。 (让 box::p
成为一个指针而不仅仅是一个标志可以避免使用 std::launder
来处理 lifetime 问题。)
立即调用的 Lambda 表达式 (IILE) 可以在这种情况和更复杂的情况下节省时间:
A a = [&] {
if (…) {
return function1();
} else {
return function2();
}
}();