0

Assuming I have a container, for the sake of argument let's say a vector:

std::vector<T> v; 

and assuming my type 'T' has a move ctor:

T(T&& move_from) noexcept //...implementation 

However I have no move assignment operator.

Is it possible to move a value to type T into a location at a certain index inside the vector ? Similar to the way I can insert the element in between two elements or at the end by moving it using:

v.emplace(std::move(value)); v.emplace_back(std::move(value)); 

... The one way everyone seems to suggest replacing a vector's element is by using:

v.at(index) = value; 

However what is bound to invoke the copy ctor (or however the opearator= copy is canonically called). It has come to my mind to use std::swap on the element at the desired index and the value I wish to move in, however, it seems to be a bit of a waste since I don't need the value I am replacing anymore AND if I don't have a swap() defined on my class the std::swap seems to just invoke the copy ctor of both elements... which just makes the whole thing twice as expensive.

How should one go about moving an element at an index in a vector and in an stl container in general (if this can be generalized) ? Is there a reason why this shouldn't be doable in the first place ?

Note, I am asking how this is doable on types that have only a standard move ctor defined, I can see it becoming fairly easy if I define a swap() on the types. However, the existence of the swap method doesn't seem to be as common so I'd prefer to avoid that... not to mention that when the method is not available, I'd have to either figure that out with sfinae (which will make code unreadable) or suffer the penalty of a double call to the copy ctor.

3
  • emplace also works, but it moves elements after the insertion point back by one slot. Commented Jul 30, 2017 at 20:56
  • 2
    what about simply v[i] = std::move(value)? Commented Jul 30, 2017 at 20:58
  • @David Haim mentioned bellow, the assumption for the question is that said operator is not defined. Should have mentioned in the post... will edit Commented Jul 30, 2017 at 21:18

1 Answer 1

4

v.at(index) = std::move(value) depends on there being a move-assignment operator. The std::swap solution needs a nothrow move-assignment operator.

Also there is definitely nothing bad about defining T::swap, it may be marginally more efficient than falling back to std::swap.

Writing the move-assignment operator for T would be a good solution. If you can't do that then it's possible to create and destroy in-place, e.g.:

T *ptr = &v.at(index); ptr->~T(); new(ptr) T( std::move(value) ); 

which relies on T's move-constructor being noexcept, otherwise you are stuffed if it throws.

A good reason to use swap or move-assignment is that it is inherently exception-safe. The move-assignment operator will be beneficial for other container operations too.

Sign up to request clarification or add additional context in comments.

9 Comments

Ah, this is the answer I was looking for.... I should have also explicitly mentioned the assumed lack of move-assignment operator. However I do have one question: Assuming the move ctor is noexcept how could the new throw ? Except for an oom error... but those tend not to happen under normal circumstances and are unrecoverable anyway.
If you don't have a move-assignment operator, then container operations that involve assignment will use copy-assignment (or fail to compile if that doesn't exist either)
Ah... nvm :p. Also I think ptr = new T(std::move(value)) might be the more normal syntax ? Is there any difference between the two ? I didn't even knew the syntax you used was valid cpp tbh...
@George your suggestion will allocate storage and create an object that is not associated with the container. The syntax new(p) means to create an object in storage that already exists at the location pointed to by p, and p->~T(); means to destroy an object without releasing its storage
Oh fair enough... that answers my next question, which was "Wouldn't that break data locality ?" :P
|

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.