Cha*_*l72 6 c++ vector move-semantics c++11
假设我有一个管理指向内部缓冲区的指针的类:
class Foo
{
public:
Foo();
...
private:
std::vector<unsigned char> m_buffer;
unsigned char* m_pointer;
};
Foo::Foo()
{
m_buffer.resize(100);
m_pointer = &m_buffer[0];
}
Run Code Online (Sandbox Code Playgroud)
现在,假设我也正确实现了3规则的东西,包括复制内部缓冲区的复制构造函数,然后将指针重新分配给内部缓冲区的新副本:
Foo::Foo(const Foo& f)
{
m_buffer = f.m_buffer;
m_pointer = &m_buffer[0];
}
Run Code Online (Sandbox Code Playgroud)
如果我还实现了移动语义,那么只复制指针并移动缓冲区是否安全?
Foo::Foo(Foo&& f) : m_buffer(std::move(f.m_buffer)), m_pointer(f.m_pointer)
{ }
Run Code Online (Sandbox Code Playgroud)
在实践中,我知道这应该工作,因为std::vector移动构造函数只是移动内部指针 - 它实际上并没有重新分配任何东西,所以m_pointer仍然指向一个有效的地址.但是,我不确定标准是否可以保证这种行为.std::vector移动语义是否保证不会发生重新分配,因此向量的所有指针/迭代器都是有效的?
我不会评论OP的代码.我正在做的就是回答这个问题:
std :: vector移动语义是否保证不会发生重新分配,因此向量的所有指针/迭代器都是有效的?
是的移动构造函数.它具有恒定的复杂性(由23.2.1/4,表96和注释B指定),因此除了从原始内存中窃取内存vector(因此不会发生内存重新分配)和清空原始内容之外,其他选择没有其他选择vector.
否为移动赋值运算符.该标准仅需要线性复杂度(如上面提到的相同段落和表中所指定的),因为有时需要重新分配.但是,在某些情况下,它可能具有恒定的复杂性(并且不执行重新分配),但它取决于分配器.(你可以在这里阅读Howard Hinnant关于移动vectors 的优秀论述.)
我会再做&m_buffer[0]一次,只是为了让您不必问这些问题。这显然不是很直观,所以不要这样做。而且,这样做,您没有任何损失。双赢。
Foo::Foo(Foo&& f)
: m_buffer(std::move(f.m_buffer))
, m_pointer(&m_buffer[0])
{}
Run Code Online (Sandbox Code Playgroud)
我对它感到满意主要是因为它是对成员m_pointer的看法m_buffer,而不是严格意义上的成员本身。
这一切都引出了一个问题......为什么会在那里?你不能公开一个成员函数给你&m_buffer[0]吗?