这似乎是一个愚蠢的问题,但是return xxx;
在一个明确定义的函数中"执行" 的确切时刻?
请参阅以下示例以了解我的意思(现在直播):
#include <iostream>
#include <string>
#include <utility>
//changes the value of the underlying buffer
//when destructed
class Writer{
public:
std::string &s;
Writer(std::string &s_):s(s_){}
~Writer(){
s+="B";
}
};
std::string make_string_ok(){
std::string res("A");
Writer w(res);
return res;
}
int main() {
std::cout<<make_string_ok()<<std::endl;
}
Run Code Online (Sandbox Code Playgroud)
我天真地期待发生的事情make_string_ok
被称为:
res
被调用(价值res
就是"A"
)w
调用构造函数return res
被执行.应该返回res的当前值(通过复制当前值res
),即"A"
.w
被称为析构函数,值res
变为"AB"
.res
函数被称为.所以我希望"A"
结果,但"AB" …
有些人不知道可以通过C中的值传递和返回结构.我的问题是关于编译器在C中返回结构时制作不必要的副本.诸如GCC之类的C编译器是使用返回值优化(RVO)优化还是仅仅是C++概念?我读过的关于RVO和copy elision的所有内容都与C++有关.
让我们考虑一个例子.我目前正在用C 实现一个双重数据类型(或者更确切地说是float-float,因为我觉得它很容易进行单元测试).请考虑以下代码.
typedef struct {
float hi;
float lo;
} doublefloat;
doublefloat quick_two_sum(float a, float b) {
float s = a + b;
float e = b - (s - a);
return (doublefloat){s, e};
}
Run Code Online (Sandbox Code Playgroud)
编译器是否会复制doublefloat
我返回的值,还是可以省略临时副本?
在C中命名的返回值优化(NRVO)怎么样?我有另一个功能
doublefloat df64_add(doublefloat a, doublefloat b) {
doublefloat s, t;
s = two_sum(a.hi, b.hi);
t = two_sum(a.lo, b.lo);
s.lo += t.hi;
s = quick_two_sum(s.hi, s.lo);
s.lo += t.lo;
s = quick_two_sum(s.hi, s.lo);
return s; …
Run Code Online (Sandbox Code Playgroud) 我正在阅读复制和交换.
我尝试阅读Copy Elision上的一些链接,但无法弄清楚它的含义.有人可以解释一下这种优化是什么,特别是下面的文字是什么意思
这不仅仅是为了方便,而且实际上是一种优化.如果参数绑定到左值(另一个非常量对象),则在创建参数时会自动创建对象的副本.但是,当s绑定到rvalue(临时对象,文字)时,通常会省略该副本,从而保存对复制构造函数和析构函数的调用.在赋值运算符的早期版本中,参数被接受为const引用,当引用绑定到右值时,不会发生复制省略.这导致创建和销毁另外的对象.
我想存储一个不平凡的类型,它是不可移动且不可复制的std::optional
。然而该对象是由自由函数构造的。(例子)
struct Foo {
Foo();
Foo(Foo const&) = delete;
Foo(Foo&&) = delete;
Foo& operator=(Foo const&) = delete; // added for completeness
Foo& operator=(Foo&&) = delete; // added for completeness
~Foo();
};
Foo foo();
Run Code Online (Sandbox Code Playgroud)
无需改变Foo
或foo()
;
感谢复制省略,我已经可以做到这一点:
Foo f1 = foo();
Run Code Online (Sandbox Code Playgroud)
这也可以编译,因为std::optional
只要求存储的类型是可破坏的:
std::optional<Foo> f2;
f2.emplace();
Run Code Online (Sandbox Code Playgroud)
但我无法填写f2
函数结果:
f2 = foo(); // no
f2.emplace(foo()); // no
Run Code Online (Sandbox Code Playgroud)
显然,因为这需要复制或移动Foo
. 这可能是不可能的,但我是否忽略了一些事情?
我有一个我static_assert
的模板结构的移动构造函数.这是否static_assert
需要编译器考虑,即使可以复制省略?
这是精简的场景:
#include <type_traits>
template<typename T>
struct X
{
X(X&&) { static_assert(std::is_same<void, T>::value, "Intentional Failure"); }
};
auto impl() -> X<int>;
auto test() -> decltype(impl())
{
return impl();
}
int main()
{
test();
}
Run Code Online (Sandbox Code Playgroud)
GCC和Clang同意评估static_assert
并且无法编译.
另一方面,MSCV和ICC编译代码就好了.
有趣的是,当我删除move
构造函数的定义时,只需将其声明为:
template<typename T>
struct X
{
X(X&&);
};
Run Code Online (Sandbox Code Playgroud)
GCC和Clang现在也编译代码.因此,所有编译器似乎都同意移动构造函数的定义与复制省略无关.
问题:
如果static_assert
复制/移动构造函数中有a ,即使可以复制/移动省略,标准是否要求对其进行评估?
(这是“ “ decltype(auto)变量是否有实际用例? ”的后续文章)
考虑以下情况-我想将一个函数传递f
给另一个函数invoke_log_return
,该函数将:
调用f
;
打印一些东西到stdout ;
返回的结果f
,避免不必要的复制/移动并允许复制省略。
请注意,如果f
抛出异常,则不应将任何内容打印到stdout。这是我到目前为止的内容:
template <typename F>
decltype(auto) invoke_log_return(F&& f)
{
decltype(auto) result{std::forward<F>(f)()};
std::printf(" ...logging here...\n");
if constexpr(std::is_reference_v<decltype(result)>)
{
return decltype(result)(result);
}
else
{
return result;
}
}
Run Code Online (Sandbox Code Playgroud)
让我们考虑各种可能性:
当f
返回prvalue时:
result
将成为一个对象;
invoke_log_return(f)
将是一个prvalue(有资格使用复制省略)。
当f
返回左值或x值:
result
将作为参考;
invoke_log_return(f)
将是一个左值或x 值。
您可以在godbolt.org上看到一个测试应用程序。如您所见, …
在摆弄复制省略时,我遇到了这种奇怪的行为:
class Obj {
public:
Obj() = default;
Obj(Obj&&) = delete;
Obj(const Obj&) { std::cout << "Copy" << std::endl; }
};
Obj f1() {
Obj o;
return o; // error C2280: move constructor is deleted
}
Obj f2() {
Obj o;
return Obj(o); // this however works fine
}
int main() {
Obj p = f1();
Obj q = f2();
return 0;
}
Run Code Online (Sandbox Code Playgroud)
GCC 和 Clang 接受此代码并且能够在两种情况下使用复制省略。
在f1()
MSVC 中抱怨它无法返回,o
因为Obj
删除了 的移动构造函数。但是,我希望它能够依靠复制构造函数。这是 MSVC 中的错误还是这种期望的行为(我不明白)和 GCC/Clang …
以下代码在Visual C++ 2013中编译良好,但不在GCC或Clang下编译.
哪个是对的?
通过隐式转换返回对象时是否需要可访问的复制构造函数?
class Noncopyable
{
Noncopyable(Noncopyable const &);
public:
Noncopyable(int = 0) { }
};
Noncopyable foo() { return 0; }
int main()
{
foo();
return 0;
}
Run Code Online (Sandbox Code Playgroud)
GCC:
error: 'Noncopyable::Noncopyable(const Noncopyable&)' is private
Noncopyable(Noncopyable const &);
^
error: within this context
Noncopyable foo() { return 0; }
Run Code Online (Sandbox Code Playgroud)
铛:
error: calling a private constructor of class 'Noncopyable'
Noncopyable foo() { return 0; }
^
note: implicitly declared private here
Noncopyable(Noncopyable const &);
^
warning: C++98 requires an …
Run Code Online (Sandbox Code Playgroud) c++ ×10
copy-elision ×10
c++17 ×4
optimization ×2
auto ×1
c ×1
c++-faq ×1
c++11 ×1
stdoptional ×1
struct ×1
visual-c++ ×1