C ++向量*不*初始化其成员? [英] C++ vector that *doesn't* initialize its members?
问题描述
我正在为一个返回大数组的C代码制作一个C ++包装,所以我试图返回一个向量中的数据< unsigned char> $ c $
现在的问题是,数据的顺序是兆字节和向量
不必要地初始化它的存储,这实际上证明我的速度减半。
如何防止这种情况? / p>
或者,如果不可能 - 是否有一些其他STL容器,可以避免这种不必要的工作?
(Pre-C ++ 11)
注意:
我传递向量作为输出缓冲区。我不从其他地方复制数据。
它是这样的:
vector< unsigned char> buf(size); //为什么要初始化?
GetMyDataFromC(& buf [0],buf.size());
默认构造函数没有显式初始化任何东西,不对unsigned char成员执行初始化:
struct uninitialized_char {
无符号字符
uninitialized_char(){}
};
//只是为了安全
static_assert(1 == sizeof(uninitialized_char),);
std :: vector< uninitialized_char> v(4 *(1 << 20));
GetMyDataFromC(reinterpret_cast< unsigned char *>(& v [0]),v.size());
我认为根据严格的别名规则,这是合法的。
当我比较 v
与向量的建构时间< unsigned char>
〜8μsvs〜12 ms。超过1000x更快。编译器是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(矢量< unsigned char>
):
clang ++ -std = c ++ 14 -stdlib = libc ++ main.cpp -DVERSION = 1 -ftrapv -Weverything -Wno-c ++ 98-compat -Wno-sign-conversion -Wno符号比较-Os&& ./a.out
初始化+第一次使用:16,425,554
数组初始化:12,228,039
第一次使用:4,197,515
第二次使用:4,404,043
VERSION = 2(矢量< uninitialized_char>
):
clang ++ -std = c ++ 14 -stdlib = libc ++ main.cpp -DVERSION = 2 -ftrapv -Weverything -Wno-c ++ 98- compat-Wno-sign-conversion -Wno-sign-comparison -Os&&& ./a.out
初始化+第一次使用:7,523,216
数组初始化:12,782
第一次使用:7,510,434
第二次使用: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 c [i] \0';
}
}
int main(){
auto start = std :: chrono :: steady_clock :: now();
#if VERSION == 1
使用element_type = unsigned char;
#elif VERSION == 2
使用element_type = uninitialized_char;
#endif
std :: vector< element_type> v(4 *(1 << 20));
auto end = std :: chrono :: contin_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<< 初始化+第一次使用:< std :: chrono :: nanoseconds(end2-start).count()< '\\\
';
std :: cout<< array initialization:< std :: chrono :: nanoseconds(end-start).count()< '\\\
';
std :: cout<< 第一次使用:< std :: chrono :: nanoseconds(end2-end).count()< '\\\
';
std :: cout<< 第二次使用:< std :: chrono :: nanoseconds(end3-end2).count()< '\\\
';
}
我使用的是clang svn-3.6.0 r218006
I'm making a C++ wrapper for a piece of C code that returns a large array, and so I've tried to return the data in a vector<unsigned char>
.
Now the problem is, the data is on the order of megabytes, and vector
unnecessarily initializes its storage, which essentially turns out to cut down my speed by half.
How do I prevent this?
Or, if it's not possible -- is there some other STL container that would avoid such needless work? Or must I end up making my own container?
(Pre-C++11)
Note:
I'm passing the vector as my output buffer. I'm not copying the data from elsewhere.
It's something like:
vector<unsigned char> buf(size); // Why initialize??
GetMyDataFromC(&buf[0], buf.size());
For default and value initialization of structs with user-provided default constructors which don't explicitly initialize anything, no initialization is performed on unsigned char members:
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());
I think this is even legal under the strict aliasing rules.
When I compared the construction time for v
vs. a vector<unsigned char>
I got ~8 µs vs ~12 ms. More than 1000x faster. Compiler was clang 3.2 with libc++ and flags: -std=c++11 -Os -fcatch-undefined-behavior -ftrapv -pedantic -Weverything -Wno-c++98-compat -Wno-c++98-compat-pedantic -Wno-missing-prototypes
C++11 has a helper for uninitialized storage, std::aligned_storage. Though it requires a compile time size.
Here's an added example, to compare total usage (times in nanoseconds):
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';
}
I'm using clang svn-3.6.0 r218006
这篇关于C ++向量*不*初始化其成员?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!