* *不*初始化其成员的C ++向量?

我正在为一个返回一个大数组的C代码做一个C ++包装器,所以我试图在一个vector<unsigned char>返回数据。

现在的问题是,数据是在兆字节的数量级vector不必要地初始化其存储,这本质上是减less了一半的速度。

我如何防止这种情况?

或者,如果这是不可能的 – 是否有其他的STL容器可以避免这种不必要的工作? 或者我必须最终制造我自己的容器?

(预C ++ 11)

注意:

我传递的vector作为我的输出缓冲区 。 我不是从其他地方复制数据。
这是像这样的:

 vector<unsigned char> buf(size); // Why initialize?? GetMyDataFromC(&buf[0], buf.size()); 

对于用户提供的缺省构造函数的默认和值初始化,这些构造函数没有明确地初始化任何东西,不对unsigned char成员执行初始化:

 struct uninitialized_char { unsigned char m; uninitialized_char() {} }; // just to be safe static_assert(1 == sizeof(uninitialized_char), ""); std::vector<uninitialized_char> v(4 * (1<<20)); GetMyDataFromC(reinterpret_cast<unsigned char*>(&v[0]), v.size()); 

我认为这在严格的走样规则下是合法的。

当我比较一个vector<unsigned char>与一个vector<unsigned char>的构造时间时,我得到了〜8μsvs〜12 ms。 比以前快1000倍 编译器clang 3.2与libc ++和标志: -std=c++11 -Os -fcatch-undefined-behavior -ftrapv -pedantic -Weverything -Wno-c++98-compat -Wno-c++98-compat-pedantic -Wno-missing-prototypes

C ++ 11有一个帮助未初始化的存储,std :: aligned_storage。 虽然它需要一个编译时间的大小。


下面是一个新增的例子,用来比较总使用率(以纳秒为单位):

VERSION = 1( vector<unsigned char> ):

 clang++ -std=c++14 -stdlib=libc++ main.cpp -DVERSION=1 -ftrapv -Weverything -Wno-c++98-compat -Wno-sign-conversion -Wno-sign-compare -Os && ./a.out initialization+first use: 16,425,554 array initialization: 12,228,039 first use: 4,197,515 second use: 4,404,043 

VERSION = 2( vector<uninitialized_char> ):

 clang++ -std=c++14 -stdlib=libc++ main.cpp -DVERSION=2 -ftrapv -Weverything -Wno-c++98-compat -Wno-sign-conversion -Wno-sign-compare -Os && ./a.out initialization+first use: 7,523,216 array initialization: 12,782 first use: 7,510,434 second use: 4,155,241 

 #include <iostream> #include <chrono> #include <vector> struct uninitialized_char { unsigned char c; uninitialized_char() {} }; void foo(unsigned char *c, int size) { for (int i = 0; i < size; ++i) { c[i] = '\0'; } } int main() { auto start = std::chrono::steady_clock::now(); #if VERSION==1 using element_type = unsigned char; #elif VERSION==2 using element_type = uninitialized_char; #endif std::vector<element_type> v(4 * (1<<20)); auto end = std::chrono::steady_clock::now(); foo(reinterpret_cast<unsigned char*>(v.data()), v.size()); auto end2 = std::chrono::steady_clock::now(); foo(reinterpret_cast<unsigned char*>(v.data()), v.size()); auto end3 = std::chrono::steady_clock::now(); std::cout.imbue(std::locale("")); std::cout << "initialization+first use: " << std::chrono::nanoseconds(end2-start).count() << '\n'; std::cout << "array initialization: " << std::chrono::nanoseconds(end-start).count() << '\n'; std::cout << "first use: " << std::chrono::nanoseconds(end2-end).count() << '\n'; std::cout << "second use: " << std::chrono::nanoseconds(end3-end2).count() << '\n'; } 

我正在使用ng svn-3.6.0 r218006

对不起,没有办法避免它。

C ++ 11增加了一个只有一个大小的构造函数,但即使这样也会对数据进行初始化。

你最好的办法就是在堆上分配一个数组,把它放在一个unique_ptr (在可用的地方),然后从那里使用它。

如果你愿意,像你所说的那样,“剽窃STL”,你总是可以拿一份EASTL来工作。 这是某些STL容器的变体,允许更多受限的内存条件。 一个恰当的实现你要做的是给它的构造函数一个特殊的值,这意味着“默认初始化成员”,这对于PODtypes意味着什么也不做什么来初始化内存。 当然,这需要使用一些模板元编程来检测它是否是PODtypes。

1似乎使用std::vector在你的情况下既不必要也不明智。 你只想要一些对象来为你pipe理一些原始的内存。 这可以很容易地通过

 std::unique_ptr<void, void(*)(void*)> p(std::malloc(n), std::free); 

2如果你真的想使用std::vector<>你可以使用这里描述的技巧。

最佳的解决scheme是简单地改变分配器对零参数construct不做任何事情。 这意味着底层types是相同的,这避免了任何types的讨厌的reinterpret_casting和潜在的别名违规,并可以非侵入性地初始化任何types。

 template<typename T> struct no_initialize : std::allocator<T> { void construct(T* p) {} template<typename... Args> void construct(T* p, Args&&... args) { new (p) T(std::forward<Args>(args)...); } }; 

如何使用vector.reserve()只分配存储但不初始化它?