我有兴趣构建一个容器uninitialized_vector
,它在语义上与std::vector
完全相同,但要注意的是,否则将使用无参数构造函数创建的新元素将不会创建初始化。我主要想避免将POD初始化为0.
据我所知,没有办法通过将
避免标准容器中元素的默认构造std::vector
与一种特殊的分配器结合来实现此目的。
我想以与std::stack
相同的方式构建我的容器,它适应用户提供的容器(在本例中为std::vector
)。换句话说,我想避免重新实现整个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:这就是你不再使用用户定义的构造函数POD的提示... –