Reputation: 614
In C++, can an instance of a class, which does not provide a default constructor, be declared and instantiated separately (in two steps).
Example:
can
std::istream_iterator<std::string>(fin) istr;
be instanciated as follows:
//declaration
std::istream_iterator<std::string> istr;
// instanciation
istr = *(new std::istream_iterator<std::string>(fin));
Is that correct? or should it be rather done like:
//declaration
std::istream_iterator<std::string> istr;
// instanciation
itPtr = new std::istream_iterator<std::string>(fin);
istr = *itPtr;
//and later: cleaning the temporary allocated object
delete itPrt;
Upvotes: 0
Views: 105
Reputation: 552
Assuming you have the following very simple class:
class A {};
then what you can do is:
A a;
or, equivalently:
A a{};
(but not A a();
since this is a forward-declaration of a function whose type is A(void)
).
In such cases the default constructor, implicitly generated by the compiler, is invoked and an object of type A
is instantiated.
Thus, with the above code lines, it is not possible to split declaration and instantiation.
Obviously the following code:
class A{};
int main() {
A a;
A* p = new A();
a=*p;
delete p;
return 0;
}
perfectly compiles. Anyway, when you perform a=*p;
then you are actually copying an (unnamed) object (from the free-store) into the object a
(previously declared and instantiated into the stack).
Upvotes: 1
Reputation: 28763
To achieve deferred initialization in C++, you typically want to use boost::optional
(or in C++17, std::optional
).
optional<your_type> op;
// code
op.emplace(arguments, to, construct, your, type);
This avoids the huge overhead associated with dynamic initialization.
In modern C++, you do not want to ever call new
or delete
. They lead to memory leaks. First prefer regular stack-allocated objects. Only if that does not work for your should you switch to using a smart pointer like std::unique_ptr
(never raw pointers that own memory).
Generally, though, a better pattern than optional (if it can work with your code) is to just declare and construct the variable in one step where it is needed. So the above example would look like:
// some code
auto const value = your_type(arguments, to, construct, your, type);
Or, equivalently,
// some code
your_type const value(arguments, to, construct, your, type);
This completely eliminates the possibility of using an object before it exists. You cannot use the object before it is constructed because there is no way to name the object until it is constructed.
Upvotes: 1
Reputation: 2617
When declaring your instance as:
std::istream_iterator<std::string> istr;
you are asking the compiler to reserve enough "space" on the stack of the program to hold an instance of type std::istream_iterator<std::string>
. The data within the instance space will be initialized according to the specified constructor or with the default constructor that applies.
When you do:
std::istream_iterator<std::string> istr;
// instanciation
itPtr = new std::istream_iterator<std::string>(fin);
istr = *itPtr;
you're effectively instiantiating istr
and then overwriting it copying the contents from the heap-allocated instance.
One case of "deferred" instantiation is when you want to specify the initialization of a member variable:
class MyClass {
private:
std::istream_iterator<std::string> istr;
public:
MyClass() : istr(std::istream_iterator<std::string>(fin)) {}
};
In this case you're specifying how the member variable should be initialized.
Upvotes: 1