【发布时间】:2019-11-23 11:41:34
【问题描述】:
考虑以下类Buffer,它包含一个std::vector 对象:
#include <vector>
#include <cstddef>
class Buffer {
std::vector<std::byte> buf_;
protected:
Buffer(std::byte val): buf_(1024, val) {}
};
现在,考虑下面的函数make_zeroed_buffer()。 BufferBuilder 类是一个 local class,它公开地派生自 Buffer。它的目的是创建Buffer 对象。
Buffer make_zeroed_buffer() {
struct BufferBuilder: Buffer {
BufferBuilder(): Buffer(std::byte{0}) {}
};
BufferBuilder buffer;
// ...
return buffer;
}
如果没有发生复制省略,是否保证将上面的buffer 对象移出?
我的理由如下:
-
return语句中的表达式buffer是一个左值。由于它是一个不再使用的本地对象,编译器将其转换为一个右值。 -
buffer对象的类型为BufferBuilder。Buffer是BufferBuilder的公共基类,所以这个BufferBuilder对象被隐式转换为Buffer对象。 - 反过来,这种转换意味着隐式引用到派生到引用到基础的转换(即,对
BufferBuilder的引用到对Buffer的引用)。对BufferBuilder的引用是一个右值引用(参见1.),它变成了对Buffer的右值引用。 -
Buffer的右值引用匹配Buffer的移动构造函数,用于构造make_zeroed_buffer()按值返回的Buffer对象。因此,返回值是通过从对象buffer的Buffer部分移动来构造的。
【问题讨论】:
-
如果没有复制省略发生 是什么让你认为这个条件永远会得到满足?据我回忆,当你明确地
return std::move(buffer);时,编译器(clang)会发出一个关于抑制复制省略的警告。 -
@Walter 是什么让您认为复制省略将永远得到满足?
-
如果我没记错的话,在这个非常特殊的情况下你必须使用
return std::move(buffer) -
无复制省略。违反下一条语句:在返回语句中,当操作数是与函数返回类型相同的类类型(忽略 cv 限定)的纯右值时
-
缓冲区对象的类型为 BufferBuilder。 Buffer是BufferBuilder的公共基类,所以这个BufferBuilder对象被隐式转换为Buffer对象。不正确。 BufferBuilder 对象被隐式复制到 Builder 对象。您对派生类的指针感到困惑。
标签: c++ c++17 move-semantics derived-class object-slicing