是否有可能创建一个模仿基本类型的构造函数语义的C ++类型?

时间:2012-04-11 20:57:35

标签: c++ default-constructor

int / double / etc的构造函数语义。是:

int a; // uninitialized
int b = int(); // zero initialized
int c = int(4); // four

是否可以定义具有完全相同行为的类?即,一个同时具有未初始化和初始化默认构造函数的构造函数?我认为这是不可能的,目前通过制作一个仅在用0调用时编译的构造函数来解决它,但是想要确保没有办法完全模仿基本类型。

8 个答案:

答案 0 :(得分:2)

这是不可能的,因为与内置类型相反,您的类构造函数将始终被调用。

如果你真的想做“未初始化的”对象(为什么????由于未初始化的变量,你有没有足够的错误吗?),你可能需要做位置new的技巧。

答案 1 :(得分:2)

如果没有定义构造函数:

struct A { int x; };

A a; // default-initialized (unintialized)
A b = A(); // value-initialized
A c = { 4 }; // four

答案 2 :(得分:2)

“未初始化的建筑”是矛盾的。

构造中缺少初始化只会由于错误而导致(无法递归构造整个对象)。

如果C ++类有构造函数,则调用它。如果由于任何原因无法调用,那么这种情况是错误的(例如传递的错误构造参数与任何构造函数都不匹配)。

C ++类可以包含基本类型的成员,其构造函数可以忽略初始化这些成员。

这可以被利用来进行优化:如果您稍后进行复杂的初始化,则可以避免写入这些成员的开销。

这就是这样做的方式,而不是试图创建一个可以保持未初始化的整个类。

如果你真的想要它,一种模拟它的方法是创建一个没有任何构造函数的POD(普通旧数据结构),然后使用一些额外的技术,以便它可以保证其初始化的方式使用。例如,从中添加一个派生类,它可以添加构造,或者使用奇怪的重复模板模式等。

如果您不希望它被初始化,您仍然可以直接使用POD。

答案 3 :(得分:1)

将始终调用默认承包商。你可以做很多“技巧”,但这取决于你想要这种行为的原因,以及你希望用户代码看起来像什么。您可以定义一个特殊的构造函数,它只是不对数据成员执行任何操作并调用它。或者,你可以做很多不同的事情......一个选择是......

你也可以玩模板......

struct uninitialized_ctor {};

class Foo
{
public:
  int x;
  Foo() : x(42)
  {
    std::cout << "Foo::Foo\n";
  }
protected:
  Foo(uninitialized_ctor const &)
  {
    std::cout << "Foo::Foo - uninitialized\n";
  }
};


struct UninitializedFoo : public Foo
{
  UninitializedFoo()
    : Foo(uninitialized_ctor())
  {
    // Does not call base class ctor...
    std::cout << "UninitializedFoo\n";
  }
};


int main(int, char *[])
{
  Foo foo1;
  UninitializedFoo foo2;
  Foo * f1 = new Foo();
  Foo * f2 = new UninitializedFoo();

  std::cout << foo1.x << '\n' << foo2.x << '\n' << f1->x << '\n' << f2->x << '\n';
}

但是 - 这取决于你的真正目标是什么......以及它如何影响代码的用户......

答案 4 :(得分:0)

这是不可能的,无论如何都会调用默认构造函数。

答案 5 :(得分:0)

聚合类类型基本上具有您喜欢的行为:

struct Foo { int a; int b; };

Foo x;   // x.a, x.b uninitialized

Foo * p = new Foo(); // p->x, p->y value-initialized, i.e. zero

Foo y { 1, 2 }; // brace-initialization does what you think

Foo z { };      // brace-initialization can also "fake" value-init for automatics

对于聚合,默认值和值初始化以递归方式传播给成员。

当然,您也可以进行非聚合,使成员未初始化:

struct Bar
{
    int a;
    int b;
    Bar() : a() { }  // no b!
    Bar(int a_, int b_) : a(a_), b(b_) { }
};

Bar x;   // x.a is value-, x.b is default-initialized

答案 6 :(得分:0)

也许你可以这样做:

template<typename T>
struct uninitialized {
    static_assert(std::is_trivially_destructible<T>::value,"T must have trivial dtor");

    alignas(T) char raw[sizeof(T)];

    template<typename... Us>
    T &initialize(Us &&... us) {
        return *(new (raw) T(std::forward<Us>(us)...));
    }

    T &get() { return reinterpret_cast<T&>(raw); }
};

需要简单的析构函数,因为否则你必须跟踪对象是否已被构造,以便适当地销毁它。

答案 7 :(得分:-1)

class A { 
public:
    A() {}

};
A* a = (A*)malloc(sizeof(A));

(孩子们,不要在家里这样做。根本不要这样做!)