컨테이너를 만드는 데 관심이 있습니다.이 컨테이너는 의미가 없으므로 std::vector
과 동일한 의미로 사용되며, 인수가없는 생성자로 생성되는 새 요소는 대신 생성되지 않습니다. 초기화. 나는 주로 POD를 0으로 초기화하는 것을 피하는 것에 관심이있다.
내가 알 수있는 한,
표준 컨테이너에서 요소의 기본 구성 피하기std::vector
을 특별한 종류의 할당 자와 결합하여 이것을 달성 할 방법이 없다.
사용자 제공 컨테이너 (내 경우 std::vector
)를 채택하는 std::stack
과 같은 컨테이너에 컨테이너를 구축하고 싶습니다. 즉, 나는 std::vector
의 전체를 다시 구현하는 것을 피하고 그 대신에 "외관"을 제공하고 싶습니다.
std::vector
의 "외부"에서 기본 구성을 제어하는 간단한 방법이 있습니까?
여기 Kerrek의 답변을 영감을 얻은 나는, 도착 솔루션입니다 :
#include <iostream>
#include <vector>
#include <memory>
#include <algorithm>
#include <cassert>
// uninitialized_allocator adapts a given base allocator
// uninitialized_allocator's behavior is equivalent to the base
// except for its no-argument construct function, which is a no-op
template<typename T, typename BaseAllocator = std::allocator<T>>
struct uninitialized_allocator
: BaseAllocator::template rebind<T>::other
{
typedef typename BaseAllocator::template rebind<T>::other super_t;
template<typename U>
struct rebind
{
typedef uninitialized_allocator<U, BaseAllocator> other;
};
// XXX for testing purposes
typename super_t::pointer allocate(typename super_t::size_type n)
{
auto result = super_t::allocate(n);
// fill result with 13 so we can check afterwards that
// the result was not default-constructed
std::fill(result, result + n, 13);
return result;
}
// catch default-construction
void construct(T *p)
{
// no-op
}
// forward everything else with at least one argument to the base
template<typename Arg1, typename... Args>
void construct(T* p, Arg1 &&arg1, Args&&... args)
{
super_t::construct(p, std::forward<Arg1>(arg1), std::forward<Args>(args)...);
}
};
namespace std
{
// XXX specialize allocator_traits
// this shouldn't be necessary, but clang++ 2.7 + libc++ has trouble
// recognizing that uninitialized_allocator<T> has a well-formed
// construct function
template<typename T>
struct allocator_traits<uninitialized_allocator<T> >
: std::allocator_traits<std::allocator<T>>
{
typedef uninitialized_allocator<T> allocator_type;
// for testing purposes, forward allocate through
static typename allocator_type::pointer allocate(allocator_type &a, typename allocator_type::size_type n)
{
return a.allocate(n);
}
template<typename... Args>
static void construct(allocator_type &a, T* ptr, Args&&... args)
{
a.construct(ptr, std::forward<Args>(args)...);
};
};
}
// uninitialized_vector is implemented by adapting an allocator and
// inheriting from std::vector
// a template alias would be another possiblity
// XXX does not compile with clang++ 2.9
//template<typename T, typename BaseAllocator>
//using uninitialized_vector = std::vector<T, uninitialized_allocator<T,BaseAllocator>>;
template<typename T, typename BaseAllocator = std::allocator<T>>
struct uninitialized_vector
: std::vector<T, uninitialized_allocator<T,BaseAllocator>>
{};
int main()
{
uninitialized_vector<int> vec;
vec.resize(10);
// everything should be 13
assert(std::count(vec.begin(), vec.end(), 13) == vec.size());
// copy construction should be preserved
vec.push_back(7);
assert(7 == vec.back());
return 0;
}
이 솔루션은 특정 공급 업체의 컴파일러 & STL의 std::vector
구현은 C++ (11)을 준수하는 정도에 따라 작동합니다.
아무것도하지 않는 기본 생성자를 정의 할 수 있습니까? 나는 컴파일러가 인라인을 할 수도 있고, 최적화가 설정된 상태에서 생략 할 수도있다. –
@Doug T.- 기본 생성자의 경우를 해결할 수 있지만 흥미로운 내용은'''resize''에서 발생하는 것 같습니다. 생성자를 호출하지 않고'''resize''와 같은 함수를 호출하는 방법이 불분명합니다. –
@Doug : 그건 당신이 더 이상 사용자 정의 생성자를 가진 포드가 아니라는 경고가 있습니다 ... –