Declaring an object before initializing it in c++
Solution 1
You can't do this directly in C++ since the object is constructed when you define it with the default constructor.
You could, however, run a parameterized constructor to begin with:
Animal a(getAppropriateString());
Or you could actually use something like the ?: operator
to determine the correct string.
(Update: @Greg gave the syntax for this. See that answer)
Solution 2
You can't use references here, since as soon as you'd get out of the scope, the reference would point to a object that would be deleted.
Really, you have two choices here:
1- Go with pointers:
Animal* a;
if( happyDay() )
a = new Animal( "puppies" ); //constructor call
else
a = new Animal( "toads" );
// ...
delete a;
or with a smart pointer
#include <memory>
std::unique_ptr<Animal> a;
if( happyDay() )
a = std::make_unique<Animal>( "puppies" );
else
a = std::make_unique<Animal>( "toads" );
2- Add an Init method to Animal
:
class Animal
{
public:
Animal(){}
void Init( const std::string& type )
{
m_type = type;
}
private:
std:string m_type;
};
Animal a;
if( happyDay() )
a.Init( "puppies" );
else
a.Init( "toads" );
I'd personally go with option 2.
Solution 3
You can't declare a variable without calling a constructor. However, in your example you could do the following:
Animal a(happyDay() ? "puppies" : "toads");
Solution 4
I prefer Greg's answer, but you could also do this:
char *AnimalType;
if( happyDay() )
AnimalType = "puppies";
else
AnimalType = "toads";
Animal a(AnimalType);
I suggest this because I've worked places where the conditional operator was forbidden. (Sigh!) Also, this can be expanded beyond two alternatives very easily.
Solution 5
If you want to avoid garbage collection - you could use a smart pointer.
auto_ptr<Animal> p_a;
if ( happyDay() )
p_a.reset(new Animal( "puppies" ) );
else
p_a.reset(new Animal( "toads" ) );
// do stuff with p_a-> whatever. When p_a goes out of scope, it's deleted.
If you still want to use the . syntax instead of ->, you can do this after the code above:
Animal& a = *p_a;
// do stuff with a. whatever
Related videos on Youtube
Comments
-
Quantum7 almost 2 years
Is it possible to declare a variable in c++ without instantiating it? I want to do something like this:
Animal a; if( happyDay() ) a( "puppies" ); //constructor call else a( "toads" );
Basially, I just want to declare a outside of the conditional so it gets the right scope.
Is there any way to do this without using pointers and allocating
a
on the heap? Maybe something clever with references?-
newacct about 15 yearssee RAII (resource acquisition is initialization)
-
Johannes Schaub - litb about 15 yearsif it is a non-static global/namespace-scope, then it's worth to note you can actually declare without initializing it: extern Animal a; ... Animal a(stuff);
-
spinkus almost 10 years@newacct: A link would help stackoverflow.com/questions/2321511/…
-
-
Uri about 15 yearsAre you sure about this? I think this will invoke default constructor and then an assignment operator, so you'll lose the old a.
-
DeadHead about 15 yearsYeah, I forgot about the initial constructor at first. That's why I usually test my code before posting it... didn't this time...
-
newacct about 15 yearsYea, but that assumes that (1) Animal has an accessible default constructor (it may not make sense to have a default constructor in some classes), (2) Animal has an assignment operator (some classes can't be assigned by design), and (3) constructing and assigning Animal has the same effect as constructing it directly.
-
Martin York about 15 yearsUsing an init() method is probably a bad idea as that implies the object is not valid after the constructor is finished.
-
DeadHead about 15 years@Martin, I don't see what's wrong with that... as it is in the OP's example, the object shouldn't be used until a value is set to it, through whatever method he is going to use.
-
Drew Hall about 15 years@DeadHead: Careful with your syntax. Your Animal a(); line is a function prototype, not a variable declaration. Animal a; is what you mean (default constructor is still invoked).
-
Ankit Roy about 15 years+1. This is the general form of the solution -- wrap it inside a function. (As you say, ?: often does the job and is more convenient when it does, but writing a separate function will always work.)
-
newacct about 15 yearsHowever, if your constructor needs to take multiple arguments, do you make multiple functions, one for each argument?
-
Uri about 15 yearsThere are some studies that show that it is better to not have constructors with multiple arguments but rather to create with default and then use setters. That being said, yes, you'd do a function per argument, or even better, have an interim struct to represent the cohesive elements that constitute the parameters, if they are related.
-
enobayram over 11 yearsDo you know if there's a way to make the placement new version guarantee correct alignment (Pre c++11)?
-
Natalie Adams over 10 yearsThis needs to be changed to auto_ptr<Animal> p_a(new Animal); otherwise the auto_ptr just has a null pointer. Though I like the second idea as it doesn't copy it - but you do have to be mindful that the life is in that scope.
-
fxam over 10 years@NathanAdams, an auto_ptr initialized with null is fine here, it will be either "puppies" or "toads" later. Having an extra "new Animal" is redundant.
-
ArtOfWarfare about 10 years-1: I've never seen a compiler that allows this. Even if it worked the way the answerer said it does, that's still a bad idea because you're constructing more objects than you need to.
-
Neurotransmitter over 7 yearsAnd I'd go with option #1. Thanks!
-
nathanfranke about 4 yearsWhen using
new
, the variable is stored in heap and should be deleted later -
Quantum7 about 4 years
std::move
definitely has potential for use here, but this code doesn't show how to get around the double initialization in the question. Could you rewrite your answer to follow my question more closely (e.g. implementing anAnimal(char *)
constructor)? You should also state that this requires C++11. -
Chronial almost 4 yearsIf you go with option 1, you should use a
unique_ptr
. -
Quantum7 almost 4 yearsThis could be a good solution. It's not quite the intended use of optional (marking values that may or may not be initialized) but it does avoid calling
a
's default constructor. -
Quantum7 almost 4 yearsNote that
optional
does have a tiny amount of overhead for storing the bool (8 bytes on my system) and initializing itself. -
Quantum7 almost 4 yearsGist exploring this (and other) solutions: gist.github.com/sbliven/359d180753febc4777ac79bb97685b5b
-
Chronial almost 4 years@Quantum7 a good compiler will completely optimize away the optional: godbolt.org/z/x9gncT
-
mr_azad about 3 yearsI like the 2 option. Thanks a log :)