요소를 완벽하게 전달하여 std :: vector를 목록 초기화 할 수 있습니까?


14

std :: vector의 집계 목록 초기화는 이동 이 더 적합 할 때 복사 초기화를 수행 한다는 것을 알았습니다 . 동시에 여러 emplace_backs가 원하는 것을 수행합니다.

나는 템플릿 함수를 작성하는이 불완전한 해결책을 생각 해낼 수 있었다 init_emplace_vector. 그러나 명시 적이 지 않은 단일 값 생성자에 대해서만 최적입니다 .

template <typename T, typename... Args>
std::vector<T> init_emplace_vector(Args&&... args)
{
  std::vector<T> vec;
  vec.reserve(sizeof...(Args));  // by suggestion from user: eerorika
  (vec.emplace_back(std::forward<Args>(args)), ...);  // C++17
  return vec;
}

질문

std :: vector를 최대한 효율적으로 초기화 하려면 emplace_back을 사용해야 합니까?

// an integer passed to large is actually the size of the resource
std::vector<large> v_init {
  1000,  // instance of class "large" is copied
  1001,  // copied
  1002,  // copied
};

std::vector<large> v_emplaced;
v_emplaced.emplace_back(1000);  // moved
v_emplaced.emplace_back(1001);  // moved
v_emplaced.emplace_back(1002);  // moved

std::vector<large> v_init_emplace = init_emplace_vector<large>(
  1000,   // moved
  1001,   // moved
  1002    // moved
);

산출

클래스 large는 복사 / 이동 (아래 구현)에 대한 정보를 생성하므로 내 프로그램의 출력은 다음과 같습니다.

- initializer
large copy
large copy
large copy
- emplace_back
large move
large move
large move
- init_emplace_vector
large move
large move
large move

대규모 클래스 구현

내 구현 large은 단순히 복사 / 이동에 대해 경고하는 큰 리소스를 보유하는 복사 가능한 / 이동 가능한 유형입니다.

struct large
{
  large(std::size_t size) : size(size), data(new int[size]) {}

  large(const large& rhs) : size(rhs.size), data(new int[rhs.size])
  {
    std::copy(rhs.data, rhs.data + rhs.size, data);
    std::puts("large copy");
  }

  large(large&& rhs) noexcept : size(rhs.size), data(rhs.data)
  {
    rhs.size = 0;
    rhs.data = nullptr;
    std::puts("large move");
  }

  large& operator=(large rhs) noexcept
  {
    std::swap(*this, rhs);
    return *this;
  }

  ~large() { delete[] data; }

  int* data;
  std::size_t size;
};

편집하다

예약을 사용하면 복사 또는 이동이 없습니다. large::large(std::size_t)생성자 만 호출됩니다. 진정한 직장.


1
집계 초기화가 아니며,을 취하는 생성자를 호출합니다 std::initializer_list.
슈퍼

std :: vector의 생성자는 혼란스러워하는 IMHO이며, 내가 당신이라면 내가 절대적으로 필요하지 않으면 실제로 들어가는 것을 피할 것입니다. 또한 벡터의 내용을 미리 알고 있다면 (이것이있을 수도 있습니다)-을 고려하십시오 std::array.
einpoklum

1
operator=소스를 파괴하는 아주 특이한 예기치 않은 문제가 발생할 수 있습니다.
알랭

1
init_emplace_vector개선 할 수vec.reserve(sizeof...(Args))
인디애나 Kernick

1
@alain operator=은 소스를 파괴하지 않습니다. 복사 스왑 관용구입니다.
RECONN

답변:


11

std :: vector를 집계 초기화 할 수 있습니까?

아니요 std::vector. 집계가 아니므로 집계 초기화 할 수 없습니다.

대신 목록 초기화를 의미 할 수 있습니다.

요소를 완벽하게 전달하여 std :: vector를 [목록 초기화] 할 수 있습니까 ?

아니요. 목록 초기화는 std::initializer_list생성자를 사용 std::initializer_list하고 인수를 복사합니다.

당신 init_emplace_vector이 요소를 emplacing 전에 메모리를 확보함으로써 개선 될 수 있지만 나타난다는 괜찮은 솔루션이 될 수 있습니다.


1
수정 해 주셔서 감사합니다. 편집했습니다. 예비와 함께 좋은 지적.
RECONN
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.