C ++向量*不*初始化其成员? [英] C++ vector that *doesn't* initialize its members?

查看:135
本文介绍了C ++向量*不*初始化其成员?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在为一个返回大数组的C代码制作一个C ++包装,所以我试图返回一个向量中的数据< unsigned char>

现在的问题是,数据的顺序是兆字节向量不必要地初始化它的存储,这实际上证明我的速度减半。



如何防止这种情况? / 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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆