2

我长期以来一直在努力解决这个问题。在 C++ 中,在类 A 中创建的类 B 的数组必须由默认构造函数初始化,这似乎是非常无效的。有没有办法避免这种行为?我实施了人员登记。如果我使用计数引用创建它,我会得到很多默认的构造函数调用,而且它似乎不太有效。我还必须创建不必要的默认构造函数。

4

4 回答 4

2

当您创建对象数组时,无论是静态数组 ( 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单独记住每个对象。

于 2013-04-03T10:51:57.330 回答
1

我想我有你想要的解决方案。我在 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   %08X\n", (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 %08X\n", (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 START\n");
    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 END\n");
    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
于 2013-04-03T12:11:16.597 回答
0

数组怎么样,B类在A里面吗?是不是像 B arr[size];?而是使用向量,以便您可以在初始化中初始化大小,然后推送对象。或带有新的动态数组,如下所示。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.
于 2013-04-03T10:58:01.063 回答
0

首先,您不需要创建默认构造函数,否则编译器将生成其代码。我认为没有一种干净的方法可以避免在对象上调用默认构造函数(也许优化器会为数组删除它),但肯定有一个肮脏的方法:

class B
{
};

class A
{
private:
    char _array[sizeof(B)*5];
    B* getB() {return (B*)_array;}
};

然后你仍然可以像使用固定大小的数组一样使用指针。sizeof并且增量/减量将不起作用。

我想你不应该被默认构造函数的“低效率”所困扰。他们在那里是有原因的。否则,如果默认构造函数真的没有工作要做,它应该被内联,然后它不会产生执行开销。

于 2013-04-03T10:53:17.063 回答