如何为全局对象,对象数组以及类/结构体内的对象调用构造函数?

时间:2021-11-12 23:03:45

How would you call the constructor of the following class in these three situations: Global objects, arrays of objects, and objects contained in another class/struct?

在这三种情况下,如何调用以下类的构造函数:全局对象,对象数组和另一个类/结构中包含的对象?

The class with the constructor (used in all three examples):

具有构造函数的类(在所有三个示例中使用):

class Foo {
    public:
        Foo(int a) { b = a; }

    private:
        int b;
};

And here are my attempts at calling this constructor:

这是我尝试调用此构造函数:

Global objects

Foo global_foo(3); // works, but I can't control when the constructor is called.

int main() {
    // ...
}

Arrays of objects

int main() {
    // Array on stack
    Foo array_of_foos[30](3); // doesn't work

    // Array on heap
    Foo *pointer_to_another_array = new Foo(3) [30]; // doesn't work
}

There I'm attempting to call the constructor for all elements of the arrays, but I'd also like to know how to call it on individual elements.

在那里,我试图为数组的所有元素调用构造函数,但我也想知道如何在单个元素上调用它。

Objects contained in classes/structs

class Bar {
    Foo foo(3); // doesn't work
};

int main() {
    Bar bar;
}

8 个解决方案

#1


9  

Global objects

Yours is the only way. On the other hand, try to avoid this. It’s better to use functions (or even other objects) as factories instead. That way, you can control the time of creation.

你的是唯一的方法。另一方面,尽量避免这种情况。最好将函数(甚至其他对象)用作工厂。这样,您就可以控制创建时间。

Arrays of objects

There’s no way to do this directly. Non-POD objects will always be default-constructed. std::fill is often a great help. You might also want to look into allocators and std::uninitialized_fill.

没有办法直接这样做。非POD对象将始终默认构造。 std :: fill通常是一个很好的帮助。您可能还想查看allocators和std :: uninitialized_fill。

Objects contained in classes/structs

Use initialization lists in your constructor:

在构造函数中使用初始化列表:

class Bar {
    Foo foo;

    Bar() : foo(3) { }
};

Static members must actually be defined outside the class:

实际上,静态成员必须在类外定义:

class Bar {
    static Foo foo;
};

Foo Bar::foo(3);

#2


4  

To correct some misconceptions about globals:

纠正一些关于全局变量的误解:

  • The order is well defined within a compilation unit.
    • It is the same as the order of definition
    • 它与定义的顺序相同

  • 订单在编译单元中定义良好。它与定义的顺序相同

  • The order across compilation units is undefined.
  • 编译单元的顺序未定义。

  • The order of destruction is the EXACT opposite of creation.
  • 破坏的顺序与创造完全相反。

Not something I recommend but: So a simple solution is to to put all globals into a single compilation unit.

不是我推荐的东西但是:所以一个简单的解决方案是将所有全局变量放入一个编译单元。

Alternatively you can tweak the use of function static variables.
Basically you can have a function the returns a reference to the global you want (defining the global inside the function). It will be created on first use (and destroyed in reverse order of creation).

或者,您可以调整函数静态变量的使用。基本上你可以有一个函数返回你想要的全局引用(定义函数内的全局)。它将在首次使用时创建(并以与创建相反的顺序销毁)。

Foo& getGlobalA() // passed parameters can be passed to constructor
{
    static Foo  A;
    return A;
}
Foo& getGlobalB()
{
    static Foo  B;
    return B;
}
etc. 

#3


2  

The Konrad reply is OK, just a puntualization about the arrays.... There is a way to create an array of items(not pointers) and here it follows:

Konrad的回复还可以,只是对阵列的简单介绍....有一种方法可以创建一个项目数组(而不是指针),下面是:

//allocate raw memory for our array
void *rawMemory = operator new[](30 * sizeof(Foo))

// point array_of_foos to this memory so we can use it as an array of Foo
Foo *array_of_foos = static_cast<Foo *>(rawMemory);

// and now we can create the array of objects(NOT pointers to the objects)
//  using the buffered new operator
for (int i = 0; i < 30; i++)
    new(array_of_foos[i])Foo(3);

This approach is described here: http://www.amazon.com/gp/product/0321334876?ie=UTF8&tag=aristeia.com-20&linkCode=as2&camp=1789&creative=9325&creativeASIN=0321334876

此处描述了此方法:http://www.amazon.com/gp/product/0321334876?ie = UTF8&tag = aristeia.com-20&linkCode = as2&camp = 1789&creative = 9325&creativeAsIN = 0321334876

#4


1  

For the global case there is no way to control when it is called. The C++ spec essentially says it will be called before main() and will be destroyed sometime afterwards. Other than that' the compiler is free to do as it pleases.

对于全局案例,无法控制何时调用它。 C ++规范基本上说它将在main()之前被调用,之后会被销毁。除此之外'编译器可以*地做,因为它喜欢。

In the first array case you are creating a static array of Foo objects. By default each value in the array will be initialized with the default constructor of Foo(). There is no way with a raw C++ array to force a particular overloaded constructor to be called. You can infer a bit of control by switching to a vector instead of an array. The vector constructor has an overloaded constructor vector(size,defaultValue) which should achieve what you are looking for. But in this case you must be careful because instead of calling Foo(3) it will call Foo(const Foo& other) where other is Foo(3).

在第一个数组中,您将创建一个Foo对象的静态数组。默认情况下,数组中的每个值都将使用Foo()的默认构造函数进行初始化。原始C ++数组无法强制调用特定的重载构造函数。您可以通过切换到向量而不是数组来推断出一些控制。向量构造函数有一个重载的构造函数向量(size,defaultValue),它应该可以实现你想要的。但在这种情况下你必须要小心,因为它不会调用Foo(3)而是调用Foo(const Foo和其他),其他的是Foo(3)。

The second array case is very similar to the first case. The only real difference is where the memory is allocated (on the heap instead of the stack). It has the same limitation with regards to calling to the constructor.

第二个数组的情况与第一个案例非常相似。唯一真正的区别在于分配内存的位置(在堆而不是堆栈上)。它在调用构造函数方面具有相同的限制。

The contained case is a different issue. C++ has a clear separation between the definition of a field within an object and the initialization of the field. To get this to work in C++ you'll need to change your Bar definition to the following

所包含的案例是另一个问题。 C ++在对象内的字段定义和字段的初始化之间有明确的区分。要使其在C ++中工作,您需要将Bar定义更改为以下内容

class Bar{
  Foo foo;
  Bar() : foo(3){}
};

#5


1  

There seems to be the general gist in this thread that you cannot initialize members of an array other than using the default constructor. One answer even creates another type, just to call another constructor. Even though you can (if the array is not part as a member of a class!):

在这个线程中似乎有一个通用要点,除了使用默认构造函数之外,你不能初始化数组的成员。一个答案甚至创建另一种类型,只是为了调用另一个构造函数。即使你可以(如果数组不是一个类的成员!):

struct foo {
    foo(int a): a(a) { }
    explicit foo(std::string s): s(s) { }
private:
    int a;
    std::string s;
};

/* global */
foo f[] = { foo("global"), foo("array") };

int main() {
    /* local */
    foo f[] = { 10, 20, 30, foo("a"), foo("b") };
}

The type, however, needs to be copy-able: The items given are copy-initialized into the members of the array.

但是,类型需要是可复制的:给定的项目被复制初始化为数组的成员。

For arrays as members in classes, it's the best to use containers currently:

对于作为类成员的数组,目前最好使用容器:

struct bar {
    /* create a vector of 100 foo's, initialized with "initial" */
    bar(): f(100, foo("initial")) { }
private:
    std::vector<foo> f;
};

Using the placement-new technique described by andy.gurin is an option too. But note it will complicate things. You will have to call destructors yourself. And if any constructor throws, while you are still building up the array, then you need to figure where you stopped... Altogether, if you want to have arrays in your class, and want to initialize them, use of a std::vector is a simple bet.

使用andy.gurin描述的放置新技术也是一种选择。但请注意,它会使事情复杂化。您必须自己调用析构函数。如果任何构造函数抛出,而你仍在构建数组,那么你需要计算停止的位置...总而言之,如果你想在你的类中有数组,并想要初始化它们,那么使用std ::矢量是一个简单的赌注。

#6


0  

Construction of arrays of objects:

构造对象数组:

You can modify your original example by using default parameters.

您可以使用默认参数修改原始示例。

Currently only the default constructor is supported.
This is something that is being addressed by the next version (because everybody asks this question)

目前仅支持默认构造函数。这是下一个版本正在解决的问题(因为每个人都会问这个问题)

#7


0  

C++0X initializer lists solve this problem for the arrays of objects case. See this Herb Sutter blog entry, where he describes them in detail.

C ++ 0X初始化列表解决了对象数组的这个问题。请参阅Herb Sutter博客文章,详细描述了这些内容。

In the meantime you might be able to work around the problem like so:

在此期间,您可以像这样解决问题:

class Foo {
public:
    Foo(int a) : b(a) {}

private:
    int b;
};

class Foo_3 : public Foo {
public:
    Foo_3() : Foo(3) {}
};

Foo_3 array_of_foos[30];

Here, the Foo_3 class exists solely for the purpose of calling the Foo constructor with the correct argument. You could make it a template even:

这里,Foo_3类仅用于使用正确的参数调用Foo构造函数。你甚至可以把它变成一个模板:

template <int i>    
class Foo_n : public Foo {
public:
    Foo_n() : Foo(i) {}
};

Foo_n<3> array_of_foos[30];

Again this might not do exactly what you want but may provide some food for thought.

这可能不是你想要的,但可能会提供一些思考的食物。

(Also note that in your Foo class you really should get into the habit of using member initializer lists instead of assignments in the constructor, as per my example above)

(另请注意,在您的Foo类中,您应该养成使用成员初始化列表而不是构造函数中的赋值的习惯,如上面的示例所示)

#8


0  

I reckon there are two ways to make sure global class objects' constructors are called safely at the time of their "creation":

我认为有两种方法可以确保在“创建”时安全地调用全局类对象的构造函数:

  1. Declare them in a namespace and make that namespace globally accessible.

    在命名空间中声明它们,并使该命名空间可全局访问。

  2. Make it a global pointer to the class object and assign a new class object to it in main(), granted code for other global objects' constructors that access the object will execute before this.

    使它成为一个指向类对象的全局指针,并在main()中为其指定一个新的类对象,为此访问该对象的其他全局对象的构造函数授予代码。

Just my two cents.

只是我的两分钱。

#1


9  

Global objects

Yours is the only way. On the other hand, try to avoid this. It’s better to use functions (or even other objects) as factories instead. That way, you can control the time of creation.

你的是唯一的方法。另一方面,尽量避免这种情况。最好将函数(甚至其他对象)用作工厂。这样,您就可以控制创建时间。

Arrays of objects

There’s no way to do this directly. Non-POD objects will always be default-constructed. std::fill is often a great help. You might also want to look into allocators and std::uninitialized_fill.

没有办法直接这样做。非POD对象将始终默认构造。 std :: fill通常是一个很好的帮助。您可能还想查看allocators和std :: uninitialized_fill。

Objects contained in classes/structs

Use initialization lists in your constructor:

在构造函数中使用初始化列表:

class Bar {
    Foo foo;

    Bar() : foo(3) { }
};

Static members must actually be defined outside the class:

实际上,静态成员必须在类外定义:

class Bar {
    static Foo foo;
};

Foo Bar::foo(3);

#2


4  

To correct some misconceptions about globals:

纠正一些关于全局变量的误解:

  • The order is well defined within a compilation unit.
    • It is the same as the order of definition
    • 它与定义的顺序相同

  • 订单在编译单元中定义良好。它与定义的顺序相同

  • The order across compilation units is undefined.
  • 编译单元的顺序未定义。

  • The order of destruction is the EXACT opposite of creation.
  • 破坏的顺序与创造完全相反。

Not something I recommend but: So a simple solution is to to put all globals into a single compilation unit.

不是我推荐的东西但是:所以一个简单的解决方案是将所有全局变量放入一个编译单元。

Alternatively you can tweak the use of function static variables.
Basically you can have a function the returns a reference to the global you want (defining the global inside the function). It will be created on first use (and destroyed in reverse order of creation).

或者,您可以调整函数静态变量的使用。基本上你可以有一个函数返回你想要的全局引用(定义函数内的全局)。它将在首次使用时创建(并以与创建相反的顺序销毁)。

Foo& getGlobalA() // passed parameters can be passed to constructor
{
    static Foo  A;
    return A;
}
Foo& getGlobalB()
{
    static Foo  B;
    return B;
}
etc. 

#3


2  

The Konrad reply is OK, just a puntualization about the arrays.... There is a way to create an array of items(not pointers) and here it follows:

Konrad的回复还可以,只是对阵列的简单介绍....有一种方法可以创建一个项目数组(而不是指针),下面是:

//allocate raw memory for our array
void *rawMemory = operator new[](30 * sizeof(Foo))

// point array_of_foos to this memory so we can use it as an array of Foo
Foo *array_of_foos = static_cast<Foo *>(rawMemory);

// and now we can create the array of objects(NOT pointers to the objects)
//  using the buffered new operator
for (int i = 0; i < 30; i++)
    new(array_of_foos[i])Foo(3);

This approach is described here: http://www.amazon.com/gp/product/0321334876?ie=UTF8&tag=aristeia.com-20&linkCode=as2&camp=1789&creative=9325&creativeASIN=0321334876

此处描述了此方法:http://www.amazon.com/gp/product/0321334876?ie = UTF8&tag = aristeia.com-20&linkCode = as2&camp = 1789&creative = 9325&creativeAsIN = 0321334876

#4


1  

For the global case there is no way to control when it is called. The C++ spec essentially says it will be called before main() and will be destroyed sometime afterwards. Other than that' the compiler is free to do as it pleases.

对于全局案例,无法控制何时调用它。 C ++规范基本上说它将在main()之前被调用,之后会被销毁。除此之外'编译器可以*地做,因为它喜欢。

In the first array case you are creating a static array of Foo objects. By default each value in the array will be initialized with the default constructor of Foo(). There is no way with a raw C++ array to force a particular overloaded constructor to be called. You can infer a bit of control by switching to a vector instead of an array. The vector constructor has an overloaded constructor vector(size,defaultValue) which should achieve what you are looking for. But in this case you must be careful because instead of calling Foo(3) it will call Foo(const Foo& other) where other is Foo(3).

在第一个数组中,您将创建一个Foo对象的静态数组。默认情况下,数组中的每个值都将使用Foo()的默认构造函数进行初始化。原始C ++数组无法强制调用特定的重载构造函数。您可以通过切换到向量而不是数组来推断出一些控制。向量构造函数有一个重载的构造函数向量(size,defaultValue),它应该可以实现你想要的。但在这种情况下你必须要小心,因为它不会调用Foo(3)而是调用Foo(const Foo和其他),其他的是Foo(3)。

The second array case is very similar to the first case. The only real difference is where the memory is allocated (on the heap instead of the stack). It has the same limitation with regards to calling to the constructor.

第二个数组的情况与第一个案例非常相似。唯一真正的区别在于分配内存的位置(在堆而不是堆栈上)。它在调用构造函数方面具有相同的限制。

The contained case is a different issue. C++ has a clear separation between the definition of a field within an object and the initialization of the field. To get this to work in C++ you'll need to change your Bar definition to the following

所包含的案例是另一个问题。 C ++在对象内的字段定义和字段的初始化之间有明确的区分。要使其在C ++中工作,您需要将Bar定义更改为以下内容

class Bar{
  Foo foo;
  Bar() : foo(3){}
};

#5


1  

There seems to be the general gist in this thread that you cannot initialize members of an array other than using the default constructor. One answer even creates another type, just to call another constructor. Even though you can (if the array is not part as a member of a class!):

在这个线程中似乎有一个通用要点,除了使用默认构造函数之外,你不能初始化数组的成员。一个答案甚至创建另一种类型,只是为了调用另一个构造函数。即使你可以(如果数组不是一个类的成员!):

struct foo {
    foo(int a): a(a) { }
    explicit foo(std::string s): s(s) { }
private:
    int a;
    std::string s;
};

/* global */
foo f[] = { foo("global"), foo("array") };

int main() {
    /* local */
    foo f[] = { 10, 20, 30, foo("a"), foo("b") };
}

The type, however, needs to be copy-able: The items given are copy-initialized into the members of the array.

但是,类型需要是可复制的:给定的项目被复制初始化为数组的成员。

For arrays as members in classes, it's the best to use containers currently:

对于作为类成员的数组,目前最好使用容器:

struct bar {
    /* create a vector of 100 foo's, initialized with "initial" */
    bar(): f(100, foo("initial")) { }
private:
    std::vector<foo> f;
};

Using the placement-new technique described by andy.gurin is an option too. But note it will complicate things. You will have to call destructors yourself. And if any constructor throws, while you are still building up the array, then you need to figure where you stopped... Altogether, if you want to have arrays in your class, and want to initialize them, use of a std::vector is a simple bet.

使用andy.gurin描述的放置新技术也是一种选择。但请注意,它会使事情复杂化。您必须自己调用析构函数。如果任何构造函数抛出,而你仍在构建数组,那么你需要计算停止的位置...总而言之,如果你想在你的类中有数组,并想要初始化它们,那么使用std ::矢量是一个简单的赌注。

#6


0  

Construction of arrays of objects:

构造对象数组:

You can modify your original example by using default parameters.

您可以使用默认参数修改原始示例。

Currently only the default constructor is supported.
This is something that is being addressed by the next version (because everybody asks this question)

目前仅支持默认构造函数。这是下一个版本正在解决的问题(因为每个人都会问这个问题)

#7


0  

C++0X initializer lists solve this problem for the arrays of objects case. See this Herb Sutter blog entry, where he describes them in detail.

C ++ 0X初始化列表解决了对象数组的这个问题。请参阅Herb Sutter博客文章,详细描述了这些内容。

In the meantime you might be able to work around the problem like so:

在此期间,您可以像这样解决问题:

class Foo {
public:
    Foo(int a) : b(a) {}

private:
    int b;
};

class Foo_3 : public Foo {
public:
    Foo_3() : Foo(3) {}
};

Foo_3 array_of_foos[30];

Here, the Foo_3 class exists solely for the purpose of calling the Foo constructor with the correct argument. You could make it a template even:

这里,Foo_3类仅用于使用正确的参数调用Foo构造函数。你甚至可以把它变成一个模板:

template <int i>    
class Foo_n : public Foo {
public:
    Foo_n() : Foo(i) {}
};

Foo_n<3> array_of_foos[30];

Again this might not do exactly what you want but may provide some food for thought.

这可能不是你想要的,但可能会提供一些思考的食物。

(Also note that in your Foo class you really should get into the habit of using member initializer lists instead of assignments in the constructor, as per my example above)

(另请注意,在您的Foo类中,您应该养成使用成员初始化列表而不是构造函数中的赋值的习惯,如上面的示例所示)

#8


0  

I reckon there are two ways to make sure global class objects' constructors are called safely at the time of their "creation":

我认为有两种方法可以确保在“创建”时安全地调用全局类对象的构造函数:

  1. Declare them in a namespace and make that namespace globally accessible.

    在命名空间中声明它们,并使该命名空间可全局访问。

  2. Make it a global pointer to the class object and assign a new class object to it in main(), granted code for other global objects' constructors that access the object will execute before this.

    使它成为一个指向类对象的全局指针,并在main()中为其指定一个新的类对象,为此访问该对象的其他全局对象的构造函数授予代码。

Just my two cents.

只是我的两分钱。