Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do you call a constructor for global objects, for arrays of objects, and for objects inside classes/structs?

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;
}
like image 286
Paige Ruten Avatar asked Nov 16 '08 19:11

Paige Ruten


People also ask

What is the constructor called for an object?

The constructor is called when an object of a class is created. It can be used to set initial values for object attributes. In Java, a constructor is a block of codes similar to the method. It is called when an instance of the class is created.

Which constructor is called when an object is defined and initialized with another object?

A copy constructor is a member function that initializes an object using another object of the same class.

Which constructor is called automatically when we create an object of the class?

Member function has a return type. 2) Constructor is automatically called when we create the object of the class. Member function needs to be called explicitly using object of class. 3) When we do not create any constructor in our class, C++ compiler generates a default constructor and insert it into our code.

What is global constructor?

Global constructors are called after initialization of other global variables and before the main() function is called. Global destructors are invoked during the exit run-time support function, similar to functions registered through atexit. Section 8.9. 2.6 discusses the format of the global constructor table.


2 Answers

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. 
like image 132
Martin York Avatar answered Oct 22 '22 12:10

Martin York


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.

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).

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

class Bar{
  Foo foo;
  Bar() : foo(3){}
};
like image 39
JaredPar Avatar answered Oct 22 '22 10:10

JaredPar