What is a good way to declare instance variables in C ++ without creating them?

I searched the topic many times on the Internet, and I really did not find a solid answer. As a C # programmer, I’m used to declaring classes in a large scope, usually at the top of the file, outside of any functions, and then constructing them when used.

Moving to C ++, the only way to replicate this is to create a default constructor, and that’s fine, but in some cases I would rather have a constructor that requires arguments than a default constructor without arguments.

After searching the Internet for a solution, I found some tips that have their drawbacks:

1. Pointers

Some people suggested having a dynamic pointer in the desired area, and then assign a pointer to indicate the location of the class when creating it.

CClass* pClass = 0; int main() { pClass = new CClass(1337); delete pClass; return 0; } 

The problem with this approach is that you have to remember that you delete the pointer later, so static pointers are much more "safe". In addition, I assume that it will be a small lack of memory, although not very, due to the presence of a pointer.

2. There is a default design by default

In any case, it is recommended to have a default constructor that 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 reset everything inside the class? What if you have another class that cannot be simply initialized to anything? What will you do if a user tries to access a function inside a class without properly initializing members? (You can verify this, but I believe that this will require too much code, especially if you have many members).

3. Staying in a smaller, more local area

There were suggestions on which people said that they remain in a small amount, pass the class as a reference to other functions that it may need, and construct it 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 which function needs something, but I can imagine a function that requires a large number of external classes that have a huge number of necessary arguments.

There are many more examples, but I can’t find what I can rely on, especially against C #, where this material is nice and light.

Thanks.

EDIT:

Let me tell you more about what I ask - 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 a class without creating it, this is what I am looking for in C ++.

Thanks again.

+6
source share
6 answers

This is a very bad habit (replaceable classes with objects):

I use to declare objects in large volumes, usually near the top of the file, outside any functions and then create them when used.

Forget it. Define an object when you need it.

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

This is C ++ thinking.

I believe in C #, this is also a bad habit. What to do if you use an object without its definition - you will get a null link exception - why play with such a dangerous thing.

BTW, the C ++ equivalent for a 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 don't need a shared object.

But do not do this, do not use global variables ...

+6
source

This is because in C # a class is a bunch of related objects. So:

FROM#

 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 ++, while it cannot be in C #.

C # provides a type of structure value that can be on the stack:

 MyStruct a; //lives on the stack 

However, I can provide a 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 

It:

 MyStruct a; //does same as above a = new Mystruct(1, 2); //aA = 1, aB = 2 
+4
source
  • Staying in a smaller, more local area

This is what you should do, and not only in C ++, but in all languages, as far as they allow.

but I can imagine a function that requires a large number of external classes having a huge number of necessary arguments.

Functions must accept the arguments they need to accept. If you feel that there are too many of them, maybe you need to reorganize the function into other parts. The number of arguments is another measure of the complexity of your function. Access to global objects not only does not simplify this function, but significantly complicates the determination of where global objects are used / modified, and which, in turn, makes your code more difficult to maintain.

If your function takes many arguments, either it is not a function, but a complex mess of different operations, or the arguments are probably grouped into some significant objects. In the latter case, just create types that represent these entities, and you will get a few arguments.

On the side of the note, I'm not sure that in C # you really do what you say you do ... in particular, most C # code is inside classes, so you are most likely used to doing classes with the members declared at the top and used everywhere. If so, you can apply the same paradigm in C ++. Create classes as many members as you need.

+2
source

It looks like you want to overload the constructor.

+1
source

Use static variables in a function to delay the creation of an object until needed.

 Foo & getInstance () { static Foo foo(arg1, arg2, ...); return foo; } void main () { Foo & x = getInstance(); } 

If you need getInstance to create a dynamic object (as in getInstance(x, y, z) ), but only pass it to the agents once, you can do:

 struct FooFactory { int arg1; float arg2; Bar arg3; bool valid; FooFactory (); Foo & getInstance (); }; FooFactory::FooFactory () : valid(false) {} Foo & FooFactory::getInstance () { if (!valid) throw Error(); static Foo foo(arg1, arg2, arg3); return foo; } FooFactor factory; void main () { factory.arg1 = ...; factory.arg2 = ...; factory.arg3 = ...; factory.valid = true; Foo & x = factory.getInstance(); } 

Of course, these are the basics. I am not going to hide information or something like that. And you can avoid factory.getInstance() by using operator() () instead of getInstance () and renaming factory to getInstance . I also do not say that this is a good idea or not. I am just showing a way in which the OP question can be literally executed.

+1
source
 //See how I'm able to do this, without calling the ctor. static AmazingClass amazing; //And then call the constructor when I want. amazing = new AmazingClass(1337); 

Everything (well, almost everything) is a reference to C #. This amazing variable does not reference anything until you highlight it through new . Here is the C ++ equivalent:

 //See how I'm able to do this, without calling the ctor. static AmazingClass * amazing; //And then call the constructor when I want. amazing = new AmazingClass(1337); 

Since (almost) everything is a reference to C # and Java, you must new this, new , that new all in these languages. You can get the same behavior in C ++ by specifying the entire pointer, but doing this is not the preferred mechanism. C ++ does not have automatic garbage collection. Everything that you highlight through new in C ++ should be deleted with delete . The preferred mechanism in C ++ is to keep new and delete to a minimum.

One way to solve the new / delete problem in C ++ is to bypass new . Just declare a variable of the required type. This gives you something you simply cannot do in Java and C #. You can declare type variables, but Java and C # do not allow you to see the objects themselves. Objects in these languages ​​are always hidden behind links.

Another way to solve the new / delete problem in C ++ is to use RAII. The new and delete commands are hidden inside the class methods, and the destructor is always cleared after itself. The class does the dirty work. For the outside world, you just use a class.

C # and C ++ are different languages. You must use different ways of thinking in order to use the two languages ​​correctly.

+1
source

Source: https://habr.com/ru/post/927784/


All Articles