10

I am primarily a c# programmer but a project I am working on has me using c++. In C# I have the ability to define a member of a class where the member is null until it is initialized. Like so:


Class Foo{
    private Bar _bar;
    public Foo(int valueBarNeeds){
        _bar = new Bar(valueBarNeeds);
    }
}

The value of _bar is null and access is prohibited until it is initialized. The rationale for this use case is that the constructor for the private object relies on some value that is not known until the parent class is constructed.

Now, in C++ I try and do the same thing:


class Foo{
public:
    Foo(int valueBarNeeds){
        _bar = new Bar(valueBarNeeds);
    }
private;
    Bar _bar;
};

The compiler throws an error saying that there is no constructor for bar that takes zero arguments. My understanding is, in C++ the new keyword means something completely different. As a part of this difference, one is able to define objects that get disposed at the end of a method without needing a manual deletion by declaring without the new keyword.


SomeFunc(){
    int valueBarNeeds = 100;
    Bar _bar(valueBarNeeds);
    _bar.SomeFunc();
}

_bar is deleted when the methods stack goes out of scope.

This then sets up my question. If the syntax that I use in C# to create unitialized objects actually tries to initialize objects in C++... How do I create an unitialized type accesible to the rest of the class methods, that gets built by the parent objects constructor?

2 Answers 2

9

The problem is that what you're calling "initialisation" is actually no such thing. Any members that are initialised, implicitly or explicitly, are initialised before the program enters your constructor body.

Your code snippets show only assignment; it doesn't matter that you're doing this in the body of a constructor for the encapsulating object. It's still just assignment.

Bar is a class so your member _bar will be implicitly initialised, but it actually cannot be because the class has no constructor taking no arguments. In order to provide arguments, you have to explicitly initialise the member yourself.

In C++ we initialise members like this:

class Foo {
public:
    Foo(int valueBarNeeds)
     : _bar(valueBarNeeds)
    {}
private:
    Bar _bar;
};

You are also right in that you are misunderstanding new a little; unlike in Java, it should be used sparingly, as objects are fundamentally created by simply declaring (and, where necessary, defining) them. The use of new is reserved for dynamic allocation in the free store and returns a pointer for use; this usage should be rare. You successfully fixed this in your final code snippet.

How do I create an unitialized type accesible to the rest of the class methods, that gets built by the parent objects constructor?

If the member is of a class type, it will always be initialised. You can't have an object that doesn't exist. The closest you can get is to encapsulate a pointer rather than an object:

class Foo {
public:
    Foo(int valueBarNeeds)
     : _bar(nullptr)
    {
       // some time later...
       _bar = new Bar(valueBarNeeds);
    }
private:
    Bar* _bar;
};

But this opens up a can of worms as regards memory management and whatnot and, as explained above, you should avoid it unless you really need it. Alternatives include smart pointers but you should still consider sticking with the bog-standard object encapsulation where possible. It should be rare that you need to deliberately leave an object in an invalid state for a time.

Sign up to request clarification or add additional context in comments.

2 Comments

In your last example, you don't actually have to initialise the _bar with a nullptr do you? Since it is a pointer, there is no constructor being called, right? (Or is it just good practice to init with nullptr?)
@null: No, you don't have to, but it's a good idea just like it always is.
3

You give your class a data member of that type, and initialize it in the constructor's initialization list:

class Foo
{
 public:
     Foo(int valueBarNeeds) :_bar(valueBarNeeds) {}
 private:
     Bar _bar;
};

Once you are in the constructor's body, all data members have been initialized. If you do not initialize them explicitly in the constructor initialization list, they get default initialized, which means the default constructor is called for user defined types, and no initialization is performed for built-in types.

1 Comment

@LightnessRacesinOrbit Copy and paste fail.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.