2017-10-13 6 views
3

std::atomic<int>과 같이 이동 또는 복사 생성자가없는 고정 된 크기의 std::vector 개체를 생성한다고 가정 해 보겠습니다. 이 경우 하위 std::atomic 클래스에는 int을 취하는 1 개 인수 생성자와 기본 생성자 (값을 0으로 초기화 함)가 있습니다.std :: vector의 배치와 같은 구조

생성자의 인수가 처음 그래서 사본을 initializer_list의 창조의 일부로서 벡터의 요소 유형 T로 변환되기 때문에, 일을하거나 움직이지 않는 std::vector<std::atomic<int>> v{1,2,3} 같은 initializer_list 구문을 사용하여이 호출됩니다. I 후에 요소 돌연변이 후 벡터를 기본적으로 구성하고있다 std::atomic<int>의 특정한 경우

: 추 비효율적 일뿐만 아니라,

std::vector<std::atomic<int>> v(3); 
v[0] = 1; 
v[1] = 2; 
v[2] = 3; 

그러나, 그것은 많은 사람 일반적인 해결책이 아니다 객체는 적절한 생성자를 호출하여 얻을 수있는 것과 동일한 사후 변형을 제공하지 않을 수 있습니다.

벡터 구축시 원하는 "emplace-like"동작을 얻을 수있는 방법이 있습니까?

+2

정말로, 나는 단지'std :: deque'를 사용할 것이다. 하지만 할 수 없다면 원하는 것을 수행하는 유일한 방법은 맞춤 할당자를 사용하는 것입니다. – Brian

+0

@Brian -'std :: deque'는이 건설 관용구를 허용합니까? – BeeOnRope

+1

'std :: deque'를 사용하면 요소를 하나씩 옮겨야 만합니다. 그러나 요소를 시작 또는 끝에 추가하면 다른 요소가 이동하지 않으므로 작동합니다. – Brian

답변

1

일반적인 해결책은 벡터가 적절한 초기화를 수행하는 사용자 정의 할당자인 construct 메서드를 만드는 것입니다. 아래 코드에서 vstd::allocator<NonMovable> 대신 MyAllocator<NonMovable> 할당자를 사용합니다. 인수가없는 construct 메서드가 호출되면 실제로 적절한 인수를 사용하여 생성자를 호출합니다. 이 방법으로 기본 생성자는 요소를 올바르게 초기화 할 수 있습니다.

은 (simplicitly를 들어,이 예에서 next_value 정적 만들었다 만했지만, 물론 MyAllocator가 구축 될 때 초기화있어 비 정적 멤버 변수가 될 수있다.)

#include <stdio.h> 
#include <memory> 
#include <new> 
#include <vector> 

struct NonMovable { 
    NonMovable(int x) : x(x) {} 
    const int x; 
}; 

template <class T> 
struct MyAllocator { 
    typedef T value_type; 
    static int next_value; 
    T* allocate(size_t n) { 
     return static_cast<T*>(::operator new(n * sizeof(T))); 
    } 
    void deallocate(T* p, size_t n) { 
     ::operator delete(p); 
    } 
    template <class U> 
    void construct(U* p) { 
     new (p) U(++next_value); 
    } 
}; 

template <class T> int MyAllocator<T>::next_value = 0; 

int main() { 
    std::vector<NonMovable, MyAllocator<NonMovable>> v(10); 
    for (int i = 0; i < 10; i++) { 
     printf("%d\n", v[i].x); 
    } 
} 

http://coliru.stacked-crooked.com/a/1a89fddd325514bf

NonMovable 클래스를 건드릴 수 없으며 생성자에 여러 인수가 필요할 수있는 유일한 해결책입니다. 당신이 각 생성자에 하나 개의 인수를 전달해야 할 경우, std::vector의 범위 생성자를 사용하므로 같은 매우 간단한 해결책이있다 :

std::vector<int> ints(10); 
std::iota(ints.begin(), ints.end(), 1); 
std::vector<NonMovable> v(ints.begin(), ints.end()); 

(비록 당신은 여분의 메모리를 감당할 수없는 경우 , 더 많은 코드가 될 커스텀 반복자를 작성해야 할 것이다.)