Home >Backend Development >C++ >Can List-Initialization Correctly Handle Vectors of Move-Only Types in C ?

Can List-Initialization Correctly Handle Vectors of Move-Only Types in C ?

DDD
DDDOriginal
2024-12-24 16:41:14920browse

Can List-Initialization Correctly Handle Vectors of Move-Only Types in C  ?

Can List-Initialization Be Used with a Vector of Move-Only Types?

When initializing a vector with move-only types using the list-initialization syntax, GCC tries to copy the unique_pointers into the vector. This behavior stems from the fact that unique_ptrs are not copyable.

Is GCC Correct in Attempting to Copy Pointers?

GCC's behavior in this case is not correct. A vector of unique_ptrs cannot be constructed by copying the pointers; instead, the move semantics must be used.

Alternative Solution

To properly initialize a vector of move-only types, it is necessary to use std::make_move_iterator to create iterators that move the pointed-to elements when dereferenced:

#include <iterator>
#include <vector>
#include <memory>

int main() {
  using move_only = std::unique_ptr<int>;
  move_only init[] = { move_only(), move_only(), move_only() };
  std::vector<move_only> v{std::make_move_iterator(std::begin(init)),
      std::make_move_iterator(std::end(init))};
}

Additional Approach

Another alternative, although not as straightforward, involves using std::enable_if and a helper struct rref_wrapper to construct a vector of move-only types:

#include <utility>
#include <type_traits>

template<class T>
struct rref_wrapper
{ // CAUTION - very volatile, use with care
  explicit rref_wrapper(T&amp;&amp; v)
    : _val(std::move(v)) {}

  explicit operator T() const{
    return T{ std::move(_val) };
  }

private:
  T&amp;&amp; _val;
};

// only usable on temporaries
template<class T>
typename std::enable_if<
  !std::is_lvalue_reference<T>::value,
  rref_wrapper<T>
>::type rref(T&amp;&amp; v){
  return rref_wrapper<T>(std::move(v));
}

// lvalue reference can go away
template<class T>
void rref(T&amp;) = delete;

Using this helper, the vector can be initialized in two steps:

std::initializer_list<rref_wrapper<move_only>> il{ rref(move_only()),
                                                   rref(move_only()),
                                                   rref(move_only()) };
std::vector<move_only> v(il.begin(), il.end());

This approach utilizes std::enable_if to ensure that rref can only be used on temporaries, thereby preventing any potential misuse.

The above is the detailed content of Can List-Initialization Correctly Handle Vectors of Move-Only Types in C ?. For more information, please follow other related articles on the PHP Chinese website!

Statement:
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn