Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What's a good way of declaring instance variables in C++ without constructing them? [closed]

Tags:

c++

scope

class

I've been searching around the internet a lot for this topic, and I haven't really reached a firm answer. As mainly a C# programmer, I'm used to declaring classes in a large scope, typically near the top of the file, outside any functions, and then constructing them when in use.

After moving on to C++, the only way of replicating this is to have a default constructor, which is fine, but in some cases, I'd rather have a constructor which requires arguments than an argument-less default constructor.

After searching around the internet for a solution, I've come across a few pieces of advice, which have their flaws:

1. Pointers

Some people have suggested to have a dynamic pointer in the desired scope, and then assign the pointer to point at the location of the class when constructed.

CClass* pClass = 0;

int main()
{
    pClass = new CClass(1337);

    delete pClass;
    return 0;
}

The problem with this approach is that you have to remember to delete the pointer afterwards, thus, static pointers are much more "safe". Also, I'm guessing there will be slight memory overhead doing this, albeit not much, due to having the pointer.

2. Have a default construct anyway

It is sometimes recommended to have a default constructor anyway, which just zeros everything inside the class:

class CClass
{
public:
    CClass() : leetNumber(0) {}
    CClass(int leetNumber) : leetNumber(leetNumber) {}
private:
    int leetNumber;
};

//Defaults leetNumber to 0 through default ctor
CClass myClass;

int main()
{
    myClass = CClass(1337);

    return 0;
}

But what happens if you can't just zero everything inside the class? What if you have another class in there which cannot just be initialized to nothing? What will you do if the user tries to access a function inside the class without proper initialization of the members? (You could check for this, but I believe it would take too much code, especially if you have a lot of members).

3. Staying in a smaller, more local scope

There have been suggestions where people have said to stay in a small scope, pass the class as a reference to other functions that may need it, and construct as soon as they declare the class:

class CClass
{
public:
    CClass(int leetNumber) : leetNumber(leetNumber) {}
    int getLeetNumber() { return leetNumber; }
private:
    int leetNumber;
};

bool GetMuchNeededAmazingNumberFromClass(CClass& myClass)
{
    if(myClass.getLeetNumber() == 1337)
        return true;

    return false;
}

int main()
{
    CClass myClass = CClass(1337);
    if(!GetMuchNeededAmazingNumberFromClass(&myClass);
        return 1;

    return 0;
}

This is good in the sense that you can see what function needs what, but I can imagine a function needing a lot of external classes having a massive amount of needed arguments.

There are many more examples, but I cannot seem to find one that I can rely on, especially coming from a C# background, where this stuff is nice and easy.

Thanks.

EDIT:

Let me elaborate more on what I'm asking for - in C#, you can do the following:

public class Program
{
    //See how I'm able to do this, without calling the ctor.
    static AmazingClass amazing;

    public static void Main()
    {
        //And then call the constructor when I want.
        amazing = new AmazingClass(1337);
    }
}

This allows me to create the class without actually constructing it, this is what I'm looking for in C++.

Thanks again.

like image 967
seandewar5 Avatar asked Oct 15 '12 20:10

seandewar5


2 Answers

This is very bad habit (replaced classes with objects):

I'm used to declaring objects in a large scope, typically near the top of the file, outside any functions, and then constructing them when in use.

Forget about it. Define object when you need it.

int main() { 
     A a;
     ...a...
     A b;
     ...b...
 }

This is C++ thinking.

I believe in C# it is bad habit too. What if you use object without defining it - you'll get null reference exception - why play with such dangerous thing.

BTW, C++ equivalent to C# object is shared_ptr:

std::shared_ptr<A> a;
int main() {
   a = std::make_shared<A>(...);
   // do not need to call delete
}

In C++ you can also use std::unique_ptr if you do not need an object to be shared.

But don't do this, don't use global variables...

like image 160
PiotrNycz Avatar answered Oct 06 '22 13:10

PiotrNycz


That's because in C# a class is a heap based, referenced object. So:

C#

MyClass a; //null reference
a = new MyClass (param1, param2);

However:

C++

MyClass a; //Myclass is constructed on stack

The C# version is equivalent to this in C++:

Myclass* a = 0; //null reference
a = new Myclass (param1, param2);

A class can live on the stack in C++, whereas it cannot in C#.

C# provides a struct value type that can live on the stack:

MyStruct a; //lives on the stack

However I can provide a struct constructor with arguments:

struct MyStruct
{
   public MyStruct (int a, int b) { /*assign to members vars*/ }

   int A, B;
}

C# code:

MyStruct a; // this creates a on stack and zero initializes int A and B

This:

MyStruct a; //does same as above

a = new Mystruct(1, 2); //a.A = 1, a.B = 2
like image 31
Science_Fiction Avatar answered Oct 06 '22 13:10

Science_Fiction