Declaring an object before initializing it in c++

56,778

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
Share:
56,778

Related videos on Youtube

Quantum7
Author by

Quantum7

Bioinformatician

Updated on July 05, 2022

Comments

  • Quantum7
    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
      newacct about 15 years
      see RAII (resource acquisition is initialization)
    • Johannes Schaub - litb
      Johannes Schaub - litb about 15 years
      if 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
      spinkus almost 10 years
      @newacct: A link would help stackoverflow.com/questions/2321511/…
  • Uri
    Uri about 15 years
    Are you sure about this? I think this will invoke default constructor and then an assignment operator, so you'll lose the old a.
  • DeadHead
    DeadHead about 15 years
    Yeah, I forgot about the initial constructor at first. That's why I usually test my code before posting it... didn't this time...
  • newacct
    newacct about 15 years
    Yea, 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
    Martin York about 15 years
    Using an init() method is probably a bad idea as that implies the object is not valid after the constructor is finished.
  • DeadHead
    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
    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
    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
    newacct about 15 years
    However, if your constructor needs to take multiple arguments, do you make multiple functions, one for each argument?
  • Uri
    Uri about 15 years
    There 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
    enobayram over 11 years
    Do you know if there's a way to make the placement new version guarantee correct alignment (Pre c++11)?
  • Natalie Adams
    Natalie Adams over 10 years
    This 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
    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
    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
    Neurotransmitter over 7 years
    And I'd go with option #1. Thanks!
  • nathanfranke
    nathanfranke about 4 years
    When using new, the variable is stored in heap and should be deleted later
  • Quantum7
    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 an Animal(char *) constructor)? You should also state that this requires C++11.
  • Chronial
    Chronial almost 4 years
    If you go with option 1, you should use a unique_ptr.
  • Quantum7
    Quantum7 almost 4 years
    This 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
    Quantum7 almost 4 years
    Note that optional does have a tiny amount of overhead for storing the bool (8 bytes on my system) and initializing itself.
  • Quantum7
    Quantum7 almost 4 years
    Gist exploring this (and other) solutions: gist.github.com/sbliven/359d180753febc4777ac79bb97685b5b
  • Chronial
    Chronial almost 4 years
    @Quantum7 a good compiler will completely optimize away the optional: godbolt.org/z/x9gncT
  • mr_azad
    mr_azad about 3 years
    I like the 2 option. Thanks a log :)