Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Move semantics with a pointer to an internal buffer

Suppose I have a class which manages a pointer to an internal buffer:

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];
}

Now, suppose I also have correctly implemented rule-of-3 stuff including a copy constructor which copies the internal buffer, and then reassigns the pointer to the new copy of the internal buffer:

Foo::Foo(const Foo& f) 
{
  m_buffer = f.m_buffer;
  m_pointer = &m_buffer[0];
}

If I also implement move semantics, is it safe to just copy the pointer and move the buffer?

Foo::Foo(Foo&& f) : m_buffer(std::move(f.m_buffer)), m_pointer(f.m_pointer)
{ }

In practice, I know this should work, because the std::vector move constructor is just moving the internal pointer - it's not actually reallocating anything so m_pointer still points to a valid address. However, I'm not sure if the standard guarantees this behavior. Does std::vector move semantics guarantee that no reallocation will occur, and thus all pointers/iterators to the vector are valid?

like image 643
Channel72 Avatar asked Jul 26 '13 11:07

Channel72


People also ask

What is Move semantics in C++?

Move semantics allows you to avoid unnecessary copies when working with temporary objects that are about to evaporate, and whose resources can safely be taken from that temporary object and used by another.

Is a buffer a pointer?

The buffer is a zone of memory, which is manipulated by you, perhaps using pointers, which in turn are manipulated by you. You must track what happens.

Are move semantics important?

Move Semantics is an extremally important concept for one to understand talking about programming in c++. It is a fundamental aspect of the language that may not be that obvious and even more for one coming from another language such as Swift, C#, or Java.


1 Answers

I'd do &m_buffer[0] again, simply so that you don't have to ask these questions. It's clearly not obviously intuitive, so don't do it. And, in doing so, you have nothing to lose whatsoever. Win-win.

Foo::Foo(Foo&& f)
   : m_buffer(std::move(f.m_buffer))
   , m_pointer(&m_buffer[0])
{}

I'm comfortable with it mostly because m_pointer is a view into the member m_buffer, rather than strictly a member in its own right.

Which does all sort of beg the question... why is it there? Can't you expose a member function to give you &m_buffer[0]?

like image 167
Lightness Races in Orbit Avatar answered Sep 25 '22 07:09

Lightness Races in Orbit