未初始化的类中的数组
An array in a class without initialization
这个问题我已经纠结很久了。在c++中,在类A中创建的类B数组必须通过默认构造函数初始化,这似乎是相当无效的。有什么方法可以避免这种行为吗?我实现了一个人员登记。如果我用count引用来创建它,我就会得到很多默认构造函数调用,而且它的效率似乎比应该的要低。我还必须创建默认构造函数,这是不必要的。
当您创建对象数组时,无论是静态数组(Person people[1000]
)还是动态分配数组(Person* people = new Person[1000]
),所有1000个对象都将被创建并使用默认构造函数初始化。
如果你想为对象创建空间,但还没有创建它们,你可以使用像std::vector这样的容器(它实现了一个动态大小的数组),或者使用指针数组,比如Person* people[1000]
或Person** people = new Person*[1000]
——在这种情况下,你可以用NULL
初始化所有的项来指示空记录,然后一个一个地分配对象:people[i] = new Person(/* constructor arguments here */)
,但是你也必须记住单独delete
每个对象。
我想我有你想要的解决方案。我在GCC 4.6上测试了这个,它可能需要修改msvc++的对齐位,但这里是示例输出和源代码:
源代码(用GCC 4.6测试):
#include <cstdio>
#include <cstring>
#include <new>
// std::alignment_of
template <typename T, std::size_t capacity>
class StaticVector
{
public:
StaticVector() : _size(0)
{
// at this point we've avoided actually initializing
// the unused capacity of the "static vector"
}
~StaticVector()
{
// deconstruct in reverse order of their addition
while (!empty())
pop_back();
}
void push_back(const T &src)
{
// at this point we initialize the unused array entry by copy
// constructing it off the passed value
new (data() + _size) T(src);
_size++;
}
void pop_back()
{
_size--;
// we manually call the deconstructor of the entry we are marking as unused
data()[_size].~T();
}
bool empty() const {return _size == 0;}
std::size_t size() const {return _size;}
// NOTE: you'd better index only into constructed data! just like an std::vector
T & operator[](int i) {return *data()[i];}
const T & operator[](int i) const {return *data()[i];}
T * data() {return reinterpret_cast<T*>(_data);}
const T * data() const {return reinterpret_cast<const T*>(_data);}
protected:
// NOTE: I only tested this on GCC 4.6, it will require some
// conditional compilation to work with MSVC and C++11
#if 1 // for GCC without c++11
char _data[sizeof(T[capacity])] __attribute__((aligned(__alignof__(T))));
#else // UNTESTED: The C++11 way of doing it?
alignas(T) char _data[sizeof(T[capacity])]; // create a suitable sized/aligned spot for the array
#endif
std::size_t _size;
};
// NOTE: lacks a default constructor, only
// constuctor that takes parameters
class B
{
public:
B(int param1, const char param2[])
{
printf("Constructing B at %08X with parameters (%i, %s)n", (int)this, param1, param2);
x = param1;
strcpy(buffer, param2);
}
~B()
{
printf("Deconstructing B at %08Xn", (int)this);
}
// NOTE: only provided to do the printf's, the default
// copy constructor works just fine
B(const B &src)
{
printf("Copying B from %08X to %08Xn", (int)(&src), (int)this);
x = src.x;
memcpy(buffer, src.buffer, sizeof(buffer));
}
protected:
int x;
char buffer[128];
};
class A
{
public:
StaticVector<B, 8> staticVectorOfB;
};
int main()
{
printf("PROGRAM STARTn");
A a;
a.staticVectorOfB.push_back(B(0, "Uno"));
a.staticVectorOfB.push_back(B(1, "Dos"));
a.staticVectorOfB.push_back(B(2, "Tres"));
printf("PROGRAM ENDn");
return 0;
}
样本输出:PROGRAM START
Constructing B at 0022FDC4 with parameters (0, Uno)
Copying B from 0022FDC4 to 0022F9A0
Deconstructing B at 0022FDC4
Constructing B at 0022FE48 with parameters (1, Dos)
Copying B from 0022FE48 to 0022FA24
Deconstructing B at 0022FE48
Constructing B at 0022FECC with parameters (2, Tres)
Copying B from 0022FECC to 0022FAA8
Deconstructing B at 0022FECC
PROGRAM END
Deconstructing B at 0022FAA8
Deconstructing B at 0022FA24
Deconstructing B at 0022F9A0
首先,您不需要创建默认构造函数,否则编译器将生成其代码。我不认为有一种干净的方法可以避免在对象上调用默认构造函数(也许优化器会为数组剥离它),但肯定有一种肮脏的方法:
class B
{
};
class A
{
private:
char _array[sizeof(B)*5];
B* getB() {return (B*)_array;}
};
那么你仍然可以像使用固定大小的数组一样使用指针。sizeof
和自增/自减将不起作用。
我想你不应该被默认构造函数的"低效"困扰太多。他们的存在是有原因的。否则,如果默认构造函数确实无事可做,则应该将其内联,这样就不会产生执行开销。
数组是怎样的,类B在A里面吗?它像B arr[size];吗?而是使用vector,这样你就可以在初始化时初始化大小,然后推入对象。或者像下面这样带有new的动态数组。initfunc可以创建你的注册。因为initfunc是在构造函数初始化时调用的,所以效率很高。
B类{
};class A
{
B *barray;
B* initfunc()
{
B* tmp = new B[5];
//init elements of B
return tmp;
}
public:
A():barray(initfunc())
{
}
~A()
{
delete[] barray;
}
};
//the code is not exception safe, vector recommended.
- C++使用整数的压缩数组初始化对象
- C++17中函数模板中的静态数组初始化(MSVC 2019)
- 从另一个静态常量数组初始化静态常量数组(只需少量计算)
- 在 Python 和 c++ 2d 数组初始化之间.这是怎麽?为什么呢?
- 字节数组初始化会导致 DirectX 崩溃
- 使用 new 和 值进行数组初始化,但没有显式数量的元素
- 运行时C++数组初始化问题
- 使用带有参数包的数组的成员数组初始化类
- 仅通过C++中数组初始化的不同方法,即可在同一输入上获得两个不同的答案
- C++ 2 个指针数组初始化 C2440
- C++结构字符数组初始化
- C++中的多维数组初始化
- constexpr数组初始化
- C++引物动态数组初始化程序的数目超过大小
- 使用std::index_sequence对std::数组初始化进行包扩展
- 当 std 数组初始化太小时,C++会引发错误吗?
- 如何确定结构数组初始化的大小?
- Qt并发错误:数组初始化需要大括号括起来的初始值设定项列表
- 此代码中的数组初始化样式是什么?这是标准的吗?
- C++ 使用数组初始化时的 STL 向量内存管理