Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/145.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 具有未初始化存储的STL向量?_C++_Optimization_Stl_Vector - Fatal编程技术网

C++ 具有未初始化存储的STL向量?

C++ 具有未初始化存储的STL向量?,c++,optimization,stl,vector,C++,Optimization,Stl,Vector,我正在编写一个内部循环,需要将structs放置在连续存储中。我不知道有多少这样的structs会提前出现。我的问题是STL的向量将其值初始化为0,因此无论我做什么,我都要承担初始化成本加上将结构的成员设置为其值的成本 是否有任何方法可以阻止初始化,或者是否存在一个类似STL的容器,其中包含可调整大小的连续存储和未初始化的元素 (我确信这部分代码需要优化,并且我确信初始化是一项巨大的成本。) 另外,请参阅下面我的评论,以了解有关何时进行初始化的说明 一些代码: void GetsCalledAL

我正在编写一个内部循环,需要将
struct
s放置在连续存储中。我不知道有多少这样的
struct
s会提前出现。我的问题是STL的
向量
将其值初始化为0,因此无论我做什么,我都要承担初始化成本加上将
结构
的成员设置为其值的成本

是否有任何方法可以阻止初始化,或者是否存在一个类似STL的容器,其中包含可调整大小的连续存储和未初始化的元素

(我确信这部分代码需要优化,并且我确信初始化是一项巨大的成本。)

另外,请参阅下面我的评论,以了解有关何时进行初始化的说明

一些代码:

void GetsCalledALot(int* data1, int* data2, int count) {
    int mvSize = memberVector.size()
    memberVector.resize(mvSize + count); // causes 0-initialization

    for (int i = 0; i < count; ++i) {
        memberVector[mvSize + i].d1 = data1[i];
        memberVector[mvSize + i].d2 = data2[i];
    }
}
void GetsCalledALot(int*data1,int*data2,int count){
int mvSize=memberVector.size()
memberVector.resize(mvSize+count);//导致0-初始化
对于(int i=0;i
使用std::vector::reserve()方法。它不会调整向量大小,但会分配空间。

错误

尝试以下方法:

std::vector<T>::reserve(x)
您看到的初始化可能是一个工件

[编辑]在关于调整大小的评论之后,我修改了代码以添加调整大小行。resize有效地调用了向量中对象的默认构造函数,但是如果默认构造函数不执行任何操作,则不会初始化任何内容。。。我仍然相信这是一个工件(我第一次设法用以下代码将整个向量归零:

#include <iostream>
#include <vector>

struct MyStruct
{
   int m_iValue00 ;
   int m_iValue01 ;
} ;

int main()
{
   MyStruct aaa, bbb, ccc ;

   std::vector<MyStruct> aMyStruct ;

   aMyStruct.push_back(aaa) ;
   aMyStruct.push_back(bbb) ;
   aMyStruct.push_back(ccc) ;

   aMyStruct.resize(6) ; // [EDIT] double the size

   for(std::vector<MyStruct>::size_type i = 0, iMax = aMyStruct.size(); i < iMax; ++i)
   {
      std::cout << "[" << i << "] : " << aMyStruct[i].m_iValue00 << ", " << aMyStruct[0].m_iValue01 << "\n" ;
   }

   return 0 ;
}
aMyStruct.push_back(MyStruct()) ;
aMyStruct.push_back(MyStruct()) ;
aMyStruct.push_back(MyStruct()) ;
所以。。。 :-/

[EDIT 2]就像Arkady已经提供的一样,解决方案是使用内联构造函数获取所需的参数

struct MyStruct
{
   MyStruct(int p_d1, int p_d2) : d1(p_d1), d2(p_d2) {}
   int d1, d2 ;
} ;
这可能会内联到您的代码中


但无论如何,您都应该使用探查器来研究代码,以确保这段代码是应用程序的瓶颈。

结构本身是否需要在连续内存中,或者是否可以不使用struct*向量


向量可以复制您添加到其中的任何内容,因此使用指针向量而不是对象向量是提高性能的一种方法。

我不认为STL是您的答案。您需要使用realloc()推出自己的解决方案。您必须存储一个指针和元素的大小或数量,并使用该指针找到在realloc()之后开始添加元素的位置

int*成员数组;
国际数组计数;
void GetsCalledALot(int*data1,int*data2,int count){
memberArray=realloc(memberArray,sizeof(int)*(arrayCount+count);
对于(int i=0;i
所以问题出在这里,resize调用insert,这是从默认构造的元素为每个新添加的元素进行复制构造。要将此成本降至0,您需要将自己的默认构造函数和复制构造函数作为空函数编写。对复制构造函数执行此操作是一个非常糟糕的ide因为它将破坏std::vector的内部重新分配算法

小结:你不能用std::vector实现这一点。

要澄清reserve()响应:你需要将reserve()与push_back()结合使用。这样,不会为每个元素调用默认构造函数,而是为复制构造函数。您仍然会受到在堆栈上设置结构,然后将其复制到向量的惩罚。另一方面,如果您使用

vect.push_back(MyStruct(fieldValue1, fieldValue2))

编译器将直接在属于向量的内存中构造新实例。这取决于优化器的智能程度。您需要检查生成的代码以找出答案。

从您对其他海报的评论来看,您似乎只剩下malloc()还有朋友。Vector不会让你有未构造的元素。

从你的代码看,你有一个结构向量,每个结构向量包含2个整数。你能改用2个整数向量吗

copy(data1, data1 + count, back_inserter(v1));
copy(data2, data2 + count, back_inserter(v2));

现在,您不必为每次复制结构而付费。

我会做一些类似的事情:

void GetsCalledALot(int* data1, int* data2, int count)
{
  const size_t mvSize = memberVector.size();
  memberVector.reserve(mvSize + count);

  for (int i = 0; i < count; ++i) {
    memberVector.push_back(MyType(data1[i], data2[i]));
  }
}
void GetsCalledALot(int*data1,int*data2,int count)
{
const size\u t mvSize=memberVector.size();
memberVector.reserve(mvSize+count);
对于(int i=0;i

您需要为存储在memberVector中的类型定义一个ctor,但这是一个很小的成本,因为它将为您提供两个方面的最佳效果;在循环期间不会进行不必要的初始化,也不会发生重新分配。

std::vector
必须以某种方式初始化数组中的值,这意味着某些构造函数(或复制构造函数)必须调用。如果要像访问已初始化的数组的未初始化部分一样访问该数组的未初始化部分,
vector
(或任何容器类)的行为是未定义的

最好的方法是使用
reserve()
push_back()
,这样就可以使用复制构造函数,避免默认构造

使用示例代码:

struct YourData {
    int d1;
    int d2;
    YourData(int v1, int v2) : d1(v1), d2(v2) {}
};

std::vector<YourData> memberVector;

void GetsCalledALot(int* data1, int* data2, int count) {
    int mvSize = memberVector.size();

    // Does not initialize the extra elements
    memberVector.reserve(mvSize + count);

    // Note: consider using std::generate_n or std::copy instead of this loop.
    for (int i = 0; i < count; ++i) {
        // Copy construct using a temporary.
        memberVector.push_back(YourData(data1[i], data2[i]));
    }
}

这样做确实意味着您必须创建自己的向量类。在这种情况下,这也会使本应是一个简单示例的内容变得复杂。但有时使用类似这样的工厂函数会更好,例如,如果插入是以其他值为条件的,则您必须无条件地构造一些昂贵的函数临时的,即使它不是实际需要的。

C++0x将一个新的成员函数模板
emplace\u back
添加到
vector
(它依赖于可变模板和完美转发),完全消除了任何临时性:

memberVector.emplace_back(data1[i], data2[i]);

如果你真的坚持让元素不被初始化
struct YourData {
    int d1;
    int d2;
    YourData(int v1, int v2) : d1(v1), d2(v2) {}
};

std::vector<YourData> memberVector;

void GetsCalledALot(int* data1, int* data2, int count) {
    int mvSize = memberVector.size();

    // Does not initialize the extra elements
    memberVector.reserve(mvSize + count);

    // Note: consider using std::generate_n or std::copy instead of this loop.
    for (int i = 0; i < count; ++i) {
        // Copy construct using a temporary.
        memberVector.push_back(YourData(data1[i], data2[i]));
    }
}
template <typename T>
class my_vector_replacement {

    // ...

    template <typename F>
    my_vector::push_back_using_factory(F factory) {
        // ... check size of array, and resize if needed.

        // Copy construct using placement new,
        new(arrayData+end) T(factory())
        end += sizeof(T);
    }

    char* arrayData;
    size_t end; // Of initialized data in arrayData
};

// One of many possible implementations
struct MyFactory {
    MyFactory(int* p1, int* p2) : d1(p1), d2(p2) {}
    YourData operator()() const {
        return YourData(*d1,*d2);
    }
    int* d1;
    int* d2;
};

void GetsCalledALot(int* data1, int* data2, int count) {
    // ... Still will need the same call to a reserve() type function.

    // Note: consider using std::generate_n or std::copy instead of this loop.
    for (int i = 0; i < count; ++i) {
        // Copy construct using a factory
        memberVector.push_back_using_factory(MyFactory(data1+i, data2+i));
    }
}
memberVector.emplace_back(data1[i], data2[i]);
auto my_uninit_array = std::unique_ptr<mystruct[]>(new mystruct[count]);
template <typename T>
struct no_init
{
    T value;

    no_init() { static_assert(std::is_standard_layout<no_init<T>>::value && sizeof(T) == sizeof(no_init<T>), "T does not have standard layout"); }

    no_init(T& v) { value = v; }
    T& operator=(T& v) { value = v; return value; }

    no_init(no_init<T>& n) { value = n.value; }
    no_init(no_init<T>&& n) { value = std::move(n.value); }
    T& operator=(no_init<T>& n) { value = n.value; return this; }
    T& operator=(no_init<T>&& n) { value = std::move(n.value); return this; }

    T* operator&() { return &value; } // So you can use &(vec[0]) etc.
};
std::vector<no_init<char>> vec;
vec.resize(2ul * 1024ul * 1024ul * 1024ul);
std::vector<T, boost::noinit_adaptor<std::allocator<T>> memberVector;
// This macro is to be defined before including VectorHijacker.h. Then you will be able to reuse the VectorHijacker.h with different objects.
#define HIJACKED_TYPE SomeStruct

// VectorHijacker.h
struct VectorHijacker
{
    std::size_t _newSize;
};


template<>
template<>
inline decltype(auto) std::vector<HIJACKED_TYPE, std::allocator<HIJACKED_TYPE>>::emplace_back<const VectorHijacker &>(const VectorHijacker &hijacker)
{
    // We're modifying directly the size of the vector without passing by the extra initialization. This is the part that relies on how the STL was implemented.
    _Mypair._Myval2._Mylast = _Mypair._Myval2._Myfirst + hijacker._newSize;
}

inline void setNumUninitialized_hijack(std::vector<HIJACKED_TYPE> &hijackedVector, const VectorHijacker &hijacker)
{
    hijackedVector.reserve(hijacker._newSize);
    hijackedVector.emplace_back<const VectorHijacker &>(hijacker);
}