I'm a seasoned C developer who is just now getting into C++, and I must admit, I'm very confused about how many ways there are to create, retain, and destroy C++ objects. In C, life is simple: assignment with = copies on the stack, and malloc/free manage data on the heap. C++ is far from that, or so it seems to me.
In light of that, here are my questions:
What are all the ways to create a C++ object? Direct/copy constructor, assignment, etc. How do they work?
What are all the different initialization syntaxes associated with all these types of object creation? What's the difference between T f = x, T f(x);, T f{x};, etc.?
Most importantly, when is it correct to copy/assign/whatever = is in C++, and when do you want to use pointers? In C, I got very used to throwing pointers around a lot, because pointer assignment is cheap but struct copying is less so. How do C++'s copy semantics affect this?
Finally, what are all these things like shared_ptr, weak_ptr, etc.?
I'm sorry if this is a somewhat broad question, but I'm very confused about when to use what (not even mentioning my confusion about memory management in collections and the new operator), and I feel like everything I knew about C memory management breaks down in C++. Is that true, or is my mental model just wrong?
To sum things up: how are C++ objects created, initialized, and destroyed, and when should I use each method?
First of all, your memory management skills are useful in C++, just they are a level below the C++ way of doing things, but they are there...
About your questions, they are a bit broad, so I'll try to keep it short:
1) What are all the ways to create a C++ object?
Same as C: they can be global variables, local automatic, local static or dynamic. You may be confused by the constructor, but simply think that every time you create an object, a constructor is called. Always. Which constructor is simply a matter of what parameters are used when creating the object.
Assignment does not create a new object, it simply copies from one oject to another, (think of memcpy but smarter).
2) What are all the different initialization syntaxes associated with all these types of object creation? What's the difference between T f = x, T f(x);, T f{x};, etc.?
T f(x) is the classic way, it simply creates an object of type T using the constructor that takes x as argument.
T f{x} is the new C++11 unified syntax, as it can be used to initialize aggregate types (arrays and such), but other than that it is equivalent to the former.
T f = x it depends on whether x is of type T. If it is, then it equivalent to the former, but if it is of different type, then it is equivalent to T f = T(x). Not that it really matters, because the compiler is allowed to optimize away the extra copy (copy elision).
T(x). You forgot this one. A temporary object of type T is created (using the same constructor as above), it is used whereever it happens in the code, and at the end of the current full expression, it is destroyed.
T f. This creates a value of type T using the default constructor, if available. That is simply a constructor that takes no parameters.
T f{}. Default contructed, but with the new unified syntax. Note that T f() is not an object of type T, but instead a function returning T!.
T(). A temporary object using the default constructor.
3) Most importantly, when is it correct to copy/assign/whatever = is in C++, and when do you want to use pointers?
You can use the same as in C. Think of the copy/assignment as if it where a memcpy. You can also pass references around, but you also may wait a while until you feel comfortable with those. What you should do, is: do not use pointers as auxiliary local variables, use references instead.
4) Finally, what are all these things like shared_ptr, weak_ptr, etc.?
They are tools in your C++ tool belt. You will have to learn through experience and some mistakes...
shared_ptr use when the ownership of the object is shared.
unique_ptr use when the ownership of the object is unique and unambiguous.
weak_ptr used to break loops in trees of shared_ptr. They are not detected automatically.
vector. Don't forget this one! Use it to create dynamic arrays of anything.
PS: You forgot to ask about destructors. IMO, destructors are what gives C++ its personality, so be sure to use a lot of them!
This is a fairly broad question, but I'll give you a starting point.
What's known in C as a "stack variable" is also called an object with "automatic storage". The lifetime of an object with automatic storage is fairly easy to understand: it's created when control reaches the point it's defined, and then destroyed when it goes out of scope:
int main() {
int foo = 5; // creation of automatic storage
do_stuff();
foo = 1;
// end of function; foo is destroyed.
}
Now, a thing to note is that = 5 is considered part of the initialization syntax, while = 1 is considered an assignment operation. I don't want you to get confused by = being used for two different things in the language's grammar.
Anyway, C++ takes automatic storage a bit further and allows arbitrary code to be run during the creation and destruction of that object: the constructors and destructors. This gives rise to the wonderful idiom called RAII, which you should use whenever possible. With RAII, resource management becomes automatic.
what are all these things like shared_ptr, weak_ptr, etc.?
Good examples of RAII. They allow you to treat a dynamic resource (malloc/free calls) as an automatic storage object!
Most importantly, when is it correct to copy/assign/whatever = is in C++, and when do you want to use pointers? In C, I got very used to throwing pointers around a lot, because pointer assignment is cheap but struct copying is less so. How do C++'s copy semantics affect this?
const references everywhere, especially for function parameters. const refs avoid copies and prevent modification of the object. If you can't use const ref, chances are a normal reference is suitable. If for some reason you want to reset the reference or set it to null, use a pointer.
What are all the ways to create a C++ object? Direct/copy constructor, assignment, etc. How do they work?
In short, all constructors create objects. Assignment doesn't. Read a book for this.
There are many ways of implicit object creating in C++ apart from explicit ones. Almost all of them use copy-constructor of the object's class. Remember: Implicit copying may require the copy constructor and/or assignment operator of a T type to be declared in public scope depending on where copying occurs. So in course:
a) explicit creation of a brand new object in stack:
T object(arg);
b) explicit copying of an existing object:
T original(arg);
...
T copy(original);
If T class has no copy constructor defined default implementation is created by compiler. It attempts to create an exact copy of the passed object. This is not always what programmer want, so custom implementation may be useful sometimes.
c) explicit creation of a brand new object in heap:
T *ptr = new T(arg);
d) implicit creation of a brand new object which constructor takes only one parameter and has no explicit modifier, for instance:
class T
{
public:
T(int x) : i(x) {}
private:
int i;
}
...
T object = 5; // actually implicit invocation of constructor occurs here
e) implicit copying of an object passed to a function by value:
void func(T input)
{
// here `input` is a copy of an object actually passed
}
...
int main()
{
T object(arg);
func(object); // copy constructor of T class is invoked before the `func` is called
}
f) implicit copying of an exception object handling by value:
void function()
{
...
throw T(arg); // suppose that exception is always raised in the `function`
...
}
...
int main()
{
...
try {
function();
} catch (T exception) { // copy constructor of T class is invoked here
// handling `exception`
}
...
}
g) Creation of a new object using assignment operator. I haven't used word 'copy' because in this case an assignment operator implementation of a particular type matters. If this operator is not implemented default implementation is created by compiler, btw it has the same behavior as default copy constructor.
class T
{
T(int x) : i(x) {}
T operator=() const
{
return T(*this); // in this implementation we explicitly call default copy constructor
}
}
...
int main()
{
...
T first(5);
T second = first; // assingment operator is invoked
...
}
Well, that's what I am able to remember without looking into Stroustrup's book. May be something is missed.
While I was writing this, some answer was accepted so I stop at this point. May the details I listed will be useful.
Related
I believe this is a common problem, but some googling does not return match, hence ask here.
So I have the following class:
class A {
public:
A(const A &rhs) { m_a = rhs.m_a; }
private:
int m_a;
};
Everything is cool until some time later, could be a year later, I add a new property, m_b to class A, but I forget to update the copy constructor.
It takes a painful debug to locate the out-of-sync.
Is there a trick to avoid such a problem, ideally at build time?
Yes, I can write unit test to cover that copy constructor, but when I forget updating copy constructor, most likely I forget that unit test also.
Turn on all your compiler warnings. You should hopefully get a warning about any uninitialized member variables. On GCC the specific flag for this is -Weffc++. See this StackOverflow post for more info.
Also, assign your values in the initializer list and not the constructor body whenever possible.
The best approach is probably to rely on the default copy constructor. For instance, your particular example, which involves a member-wise copy, works fine with the default constructor (i.e., the behavior would be the same even if you simply deleted the constructor). As more members are added, they will automatically receive the same member-wise copy behavior in the default constructor.
In some unusual cases you might want to force the generation of the default constructor (e.g., when you want to have some different, explicitly defined behavior for non-const source objects). In that case, in C++11 and later, you can explicitly request the default copy constructor as follows:
A(const A&) = default;
Some coding guidelines also recommend always including the above explicit request for the default constructor simply as a form of documentation.
Mostly member-wise, with exceptions
Sometimes, most member of a class are fine with the default member-wise copy, but you have a couple of exceptions. An example would be a raw pointer where you want to perform a deep copy of the underlying data. By default, the pointer is simply copied and so the pointers in the source object and new object will both point to the same location in memory.
The solution is fairly simple: just wrap this pointer and any associated meta-data (e.g., a length field if the pointed to object is an array) in a suitable RAII wrapper whose copy constructor performs the specific non-default behavior you want, and include a member of this type in your class A. Now A can continue to use the default copy constructor, which calls your explicit copy constructor for your pointer. Essentially, you are back to the pure member-wise copy, but with the new semantics for your pointer-wrapping member.
This type of matter will also help you keep your destructor and sometimes your constructors trivial as well. No doubt the original class above had some code to delete your raw pointer. Once wrapped with the copying-RAII wrapper, the wrapper takes care of destruction and so the containing class doesn't have to, and often the destructor can be removed entirely.
This wrapper approach often has zero or close to zero overhead in a language like C++.
You can find some more details in this question.
When that doesn't work
Sometimes the above may not work. One example would be when the copy constructor needs to embed the address (the this pointer) of the new object in some field. The self-contained wrapper doesn't have a way to get the this pointer of the containing object (indeed, it doesn't even know it is a member).
One approach here is to create a new sub-object with all of the fields of your original object that use the default copy behavior, and then create your new top level object by aggregating (or by inheritance) this sub-object with the few fields that do need special treatment. Then you can keep the using the default copy constructor for all the fields that should have the default treatment.
This approach can even have performance benefits, since compilers are likely to use a pure memcpy approach1 for the sub-object, in addition to calling your explicit code for the exceptional fields. When the fields were mingled together in the original object, this is much less likely or impossible (e.g., because the layout of the object may interleave the exceptional fields and default-copied fields).
1 This doesn't actually mean that there will be a call to the standard library memcpy in the code: for small objects the compiler will usually unroll this for small objects into an unrolled sequence of mostly maximum width loads and stores.
The only time you ever need to write copy constructors, assignment operators or destructors is if your class is an RAII wrapper for exactly one resource.
If your class is managing more than one resource, it's time to refactor it so that it's composed of classes which manage exactly one resource.
example:
#include <algorithm>
// this class is managing two resources.
// This will be a maintenance nightmare and will required
// horribly complicated constructor code.
struct DoubleVector
{
int *vec1;
int *vec2;
};
// this class manages a single resource
struct SingleVector
{
SingleVector() : vec (new int[10]) {}
SingleVector(SingleVector const& other)
: vec (new int[10])
{
// note - simple constructor
std::copy(other.vec, other.vec + 10, vec);
}
SingleVector& operator=(SingleVector const& other)
{
auto temp = other;
std::swap(vec, temp.vec);
return *this;
}
~SingleVector() {
delete [] vec;
}
// note - single resource
int *vec;
};
// this class uses *composition* and default assignment/construction/destruction
// it will never go wrong. And it could not be simpler.
struct DoubleVectorDoneRight
{
SingleVector vec1;
SingleVector vec2;
};
int main()
{
SingleVector v;
SingleVector v2 = v;
SingleVector v3;
v3 = v;
}
Conceptual Question
Say we have simple example like this:
void foo(std::unique_ptr<int> ptr)
{
std::cout << *ptr.get() << std::endl;
}
int main()
{
std::unique_ptr<int> uobj = std::make_unique<int>(4);
foo(uobj ); // line-(1) Problem ,but Alternative -> foo(std::move(uobj ))
std::unique_ptr<int> uobjAlt = uobj; // line-(2) Problem ,but Alternative -> std::unique_ptr<int> uobjAlt = std::move(uobj);
return EXIT_SUCCESS;
}
We know simply std::unique_ptr bound with concept of resource owning by single owner with moving resource among multiple owners while shared_ptr has opposite aspect.
As example shown above, when you look at line-(1) & line-(2) you notice that some standard rules are being violated because std::unique_ptr has(deleted) no both copy constructors and copy assignable operators defined, but In order to avoid compilation errors we have to use std::move function instead.
Problem
Why modern C++ compiler cannot automatically generate instructions to move the resource among unique pointers in line-(1) and line-(2)? because we know unique pointer intentionally design for that. Why should we use std::move explicitly to instruct the machine to move ownership of the resource?
std::unique_ptr nothing but class template.we know that, But situations addressed in line-1 and line -2 having issues while compiler complain about copying unique_pointers not allowed(deleted functions).why we having these kind of errors why c++ standard and compiler vendors cannot override this concept?
Unique Pointer intentionally designed for the purpose of moving resource while passing its ownership, when we pass it as function/constructor argument or assign to another unique pointer, it conceptually should move resource with ownership nothing else, but why we should use std::move to convey compiler to actual move, why don't we have a freedom to call line-(1) and line-(2) as it is? (while intelligent compiler generate automatic move operation among unique pointers for us, unless there is const or non-const reference passing).
(Sorry for long description and broken English) Thank you.
unique_ptr is useful to free memory for you automatically when uobj goes out of scope. That's its job. So, since it has 1 pointer it has to free, it has to be unique, and hence its name: unique_ptr!
When you do something like this:
std::unique_ptr<int> uobjAlt = uobj;
You're issuing a copy operation, but, you're not supposed to copy the pointer, because copying means that both objects uobjAlt and uobj must both be freed, which will directly lead to a segmentation fault and a crash. So, by using std::move, you're moving ownership from one object to another.
If you want to have multiple pointers to a single object, you should consider using std::shared_ptr.
This has nothing to do with whether the compiler can do this. It certainly could work that way, and in fact, it did work that way prior to C++11 with std::auto_ptr<>. It was horrible.
std::auto_ptr<int> x = std::auto_ptr<int>(new int(5));
std::auto_ptr<int> y = x;
// Now, x is NULL
The problem here is that the = sign usually means "copy from x to y", but in this case what is happening is "move from x to y, invalidating x in the process". Yes, if you are a savvy programmer you would understand what is going on here and it wouldn't surprise you, at least not all of the time. However, in more common situations it would be horribly surprising:
Here's MyClass.h:
class MyClass {
private:
std::auto_ptr<Type> my_field;
...
};
Here's MyClass.cpp:
void MyClass::Method() {
SomeFunction(my_field);
OtherFunction(my_field);
}
Here's Functions.h:
// Which overload, hmm?
void SomeFunction(Type &x);
void SomeFunction(std::auto_ptr<Type> x);
void OtherFunction(const std::auto_ptr<Type> &x);
Now you have to look at three different files before you can figure out that my_field is set to NULL. With std::unique_ptr you only have to look at one:
void MyClass::Method() {
SomeFunction(std::move(my_field));
OtherFunction(my_field);
}
Just looking at this one function I know that it's wrong, I don't have to figure out which overload is being used for SomeFunction, and I don't have to know what the type of my_field is. There's definitely a balance that we need to have between making things explicit and implicit. In this case, the fact that you couldn't explicitly tell the difference between moving and copying a value in C++ was such a problem that rvalue references, std::move, std::unique_ptr, etc. were added to C++ to clear things up, and they're pretty amazing.
The other reason why auto_ptr was so bad is because it interacted poorly with containers.
// This was a recipe for disaster
std::vector<std::auto_ptr<Type> > my_vector;
In general, many templates worked poorly with auto_ptr, not just containers.
If the compiler were allowed to auto-infer move semantics for types such as std::unique_ptr, code like this would break:
template<typename T> void simple_swap(T& a, T& b) {
T tmp = a;
a = b;
b = tmp;
}
The above counts on tmp being a copy of a (because it continues to use a as the left-hand side of as assignment operator). There is code in the standard algorithms which actually requires temporary copies of container values. Inferring moves would break them, causing crashes at run-time. This is why std::auto_ptr was warned against ever being used in STL containers.
Is it possible to force C++ to construct an object in the scope of a calling function? What I mean is to explicitly do what an return value optimization (RVO) does.
I have some container classes which are in a chain of derivation. Since the classes are constructed with stack data, they can't be returned, so I disabled the copy constructor and assignment operators. For each class, I am providing an iterator. The constructor of each iterator has only one argument: a pointer to the container class. To get the iterator, I want to use this function:
BindPackIterator BindPack.begin(void)
{
return BindPackIterator(this);
}
in this context:
for (auto i=bindpack.begin(); !i.end(); ++i) { i.run(); }
The compiler issues errors, complaining about not being able to copy the BindPackIterator object. Remember, I disabled them.
What I want to happen is for the BindPackIterator to be instantiated in the calling function's scope to avoid either a copy or move operation.
In this particular case, I know I can do a workaround, changing the begin function to return a BindPack pointer,
for(BindPackIterator i=bindpack.begin(); !i.end(); ++i) { i.run(); }
and I've experimented a bit, without success, with decltype and this construction:
auto BindPack::begin(void) -> BindPackIterator
{
return BindPackIterator(this);
}
This is just the example with which I'm currently frustrated. There have been other projects where the obvious solution is for the function to instantiate an object in the calling function's scope. The move constructor (foo&&) helps in some cases, but for objects with many data members, even that can be inefficient. Is there a design pattern that allows object construction/instantiation in the caller's scope?
Putting n.m.'s comment into code, write a constructor for BindPackIterator that takes a BindPack and initializes the iterator in the "begin" state. e.g:
BindPackIterator(BindPack* pack) : pack(pack), pos(0){ }
That you can use in your for loop:
BindPack pack;
for(BindPackIterator i(&pack); !i.end(); ++i){
i.run();
}
Live demo
Is it fair to say that the answer is "No," it is not possible to construct a returned object in the calling function's scope? Or in other words, you can't explicitly tell the compiler to use RVO.
To be sure, it is a dangerous possibility: stack memory used to construct the object while available in the called function will not be valid in the calling function, even though the values might remain untouched in the abandoned stack frame. This would result in unpredictable behavior.
Upon further consideration, while summing up at the end of this response, I realized that the compiler may not be able to accurately predict the necessary stack size for objects created in the calling function and initialized in a called function, and it would not be possible to dynamically expand the stack frame if the execution had passed to another function. These considerations make my whole idea impossible.
That said, I want to address the workarounds that solve my iterator example.
I had to abandon the idea of using auto like this:
for (auto i=bindpack.begin(); !i.end(); ++i)
Having abandoned auto, and realizing that it's more sensible to explicitly name the variable anyway (if the iterator is different enough to require a new class, it's better to name it to avoid confusion) , I am using this constructor:
BindPackIterator(BindPack &ref) : m_ref_pack(ref), m_index(0) { }
in order to be able to write:
for (BindPackIterator i=bindpack; !i.end(); ++i)
preferring to initialize with an assignment. I used to do this when I was last heavily using C++ in the late 1990's, but it's not been working for me recently. The compiler would ask for a copy operator I didn't want to define for reasons stated above. Now I think that problem was due to my collection of constructors and assignment operators I define to pass the -Weffc++ test. Using simplified classes for this example allowed it to work.
Another workaround for an object more complicated than an iterator might be to use a tuple for the constructor argument for objects that need multiple variables to initialize. There could be a casting operator that returns the necessary tuple from the class that initializes the object.
The constructor could look like:
FancyObject(BigHairyTuple val) : m_data1(get<0>(val)), m_data2(get<1>(val), etc
and the contributing object would define this:
class Foo
{
...
operator BigHairyTuple(void) {
return BigHairyTuple(val1, val2, ...);
}
};
to allow:
FancyObject fo = foo;
I haven't tested this specific example, but I'm working with something similar and it seems likely to work, with some possible minor refinements.
I'm not a very experienced c++ coder and this has me stumped. I am passing a object (created elsewhere) to a function, I want to be able to store that object in some array and then run through the array to call a function on that object. Here is some pseudo code:
void AddObject(T& object) {
object.action(); // this works
T* objectList = NULL;
// T gets allocated (not shown here) ...
T[0] = object;
T[0].action(); // this doesn't work
}
I know the object is passing correctly, because the first call to object.action() does what it should. But when I store object in the array, then try to invoke action() it causes a big crash.
Likely my problem is that I simply tinkered with the .'s and *'s until it compiled, T[0].action() compliles but crashes at runtime.
The simplest answer to your question is that you must declare your container correctly and you must define an appropriate assigment operator for your class. Working as closely as possible from your example:
typedef class MyActionableClass T;
T* getGlobalPointer();
void AddInstance(T const& objInstance)
{
T* arrayFromElsewhere = getGlobalPointer();
//ok, now at this point we have a reference to an object instance
//and a pointer which we assume is at the base of an array of T **objects**
//whose first element we don't mind losing
//**copy** the instance we've received
arrayFromElsewhere[0] = objInstance;
//now invoke the action() method on our **copy**
arrayFromElsewhere[0].action();
}
Note the signature change to const reference which emphasizes that we are going to copy the original object and not change it in any way.
Also note carefully that arrayFromElsewhere[0].action() is NOT the same as objInstance.action() because you have made a copy — action() is being invoked in a different context, no matter how similar.
While it is obvious you have condensed, the condensation makes the reason for doing this much less obvious — specifying, for instance, that you want to maintain an array of callback objects would make a better case for “needing” this capability. It is also a poor choice to use “T” like you did because this tends to imply template usage to most experienced C++ programmers.
The thing that is most likely causing your “unexplained” crash is that assignment operator; if you don't define one the compiler will automatically generate one that works as a bitwise copy — almost certainly not what you want if your class is anything other than a collection of simple data types (POD).
For this to work properly on a class of any complexity you will likely need to define a deep copy or use reference counting; in C++ it is almost always a poor choice to let the compiler create any of ctor, dtor, or assignment for you.
And, of course, it would be a good idea to use standard containers rather than the simple array mechanism you implied by your example. In that case you should probably also define a default ctor, a virtual dtor, and a copy ctor because of the assumptions made by containers and algorithms.
If, in fact, you do not want to create a copy of your object but want, instead, to invoke action() on the original object but from within an array, then you will need an array of pointers instead. Again working closely to your original example:
typedef class MyActionableClass T;
T** getGlobalPointer();
void AddInstance(T& objInstance)
{
T** arrayFromElsewhere = getGlobalPointer();
//ok, now at this point we have a reference to an object instance
//and a pointer which we assume is at the base of an array of T **pointers**
//whose first element we don't mind losing
//**reference** the instance we've received by saving its address
arrayFromElsewhere[0] = &objInstance;
//now invoke the action() method on **the original instance**
arrayFromElsewhere[0]->action();
}
Note closely that arrayFromElsewhere is now an array of pointers to objects instead of an array of actual objects.
Note that I dropped the const modifier in this case because I don’t know if action() is a const method — with a name like that I am assuming not…
Note carefully the ampersand (address-of) operator being used in the assignment.
Note also the new syntax for invoking the action() method by using the pointer-to operator.
Finally be advised that using standard containers of pointers is fraught with memory-leak peril, but typically not nearly as dangerous as using naked arrays :-/
I'm surprised it compiles. You declare an array, objectList of 8 pointers to T. Then you assign T[0] = object;. That's not what you want, what you want is one of
T objectList[8];
objectList[0] = object;
objectList[0].action();
or
T *objectList[8];
objectList[0] = &object;
objectList[0]->action();
Now I'm waiting for a C++ expert to explain why your code compiled, I'm really curious.
You can put the object either into a dynamic or a static array:
#include <vector> // dynamic
#include <array> // static
void AddObject(T const & t)
{
std::array<T, 12> arr;
std::vector<T> v;
arr[0] = t;
v.push_back(t);
arr[0].action();
v[0].action();
}
This doesn't really make a lot of sense, though; you would usually have defined your array somewhere else, outside the function.
is it possible to re-initialize an object of a class using its constructor?
Sort of. Given a class A:
A a;
...
a = A();
the last statement is not initialisation, it is assignment, but it probably does what you want.
Literally? Yes, by using placement new. But first you have to destruct the previously constructed object.
SomeClass object(1, 2, 3);
...
object.~SomeClass(); // destruct
new(&object) SomeClass(4, 5, 6); // reconstruct
...
// Final destruction will be done implicitly
The value of this does not go beyond purely theoretical though. Don't do it in practice. The whole thing is ugly beyond description.
It's possible, although it's a very bad idea. The reason why is that without calling the destructors on the existing object, you are going to leak resources.
With that major caveat, if you insist on doing it, you can use placement new.
// Construct the class
CLASS cl(args);
// And reconstruct it...
new (&cl) CLASS(args);
In C++11, you can do this:
#include <type_traits>
template <class T, typename... Args>
void Reconstruct(T& x, Args&&... args)
{
static_assert(!std::has_virtual_destructor<T>::value, "Unsafe");
x.~T();
new (&x) T(std::forward<Args>(args)...);
}
This allows you to use Reconstruct passing arbitrary constructor parameters to any object. This can avoid having to maintain a bunch of Clear methods, and bugs that can easily go unnoticed if at some point the object changes, and the Clear method no longer matches the constructor.
The above will work fine in most contexts, but fail horribly if the reference is to a base within a derived object that has a virtual destructor. For this reason, the above implementation prevents use with objects that have a virtual destructor.
Short answer:
No. If part of your object's intended behavior is to be initialized several times, then the best way to implement this is through an accessible initialization method. The constructor of your class can simply defer to this method.
class C1 {
public:
C1(int p1, int p2) {
Init(p1,p2);
}
void Init(int p1, int p2) { ... }
};
Nitpicker corner:
Is there some incredibly evil way to call a constructor in C++ after an object is created? Almost certainly, this is C++ after all. But it's fundamentally evil and it's behavior is almost certainly not defined by the standard and should be avoided.
No, constructors are only called when the object is first created. Write a new method to do it instead.
Edit
I will not acknowledge placement new, because I don't want to have to get a pet raptor for work.
See this comic, but think of the topic on hand...
Yes you can cheat and use placement new.
Note: I do not advice this:
#include <new>
reInitAnA(A& value)
{
value.~A(); // destroy the old one first.
new (&value) A(); // Call the constructor
// uses placement new to construct the new object
// in the old values location.
}
I usually write the following in modern C++ :
SomeClass a;
...
a = decltype(a)();
It may be not the most effective way, as it effectively constructs another object of the same type of a and assigns it to a, but it works in most cases, you don't have to remember the type of a, and it adapts if the type changes.
Instead of destructing and reinitializing as suggested by some of the answers above, it's better to do an assignment like below. The code below is exception safe.
T& reinitialize(int x, int y)
{
T other(x, y);
Swap(other); // this can't throw.
return *this;
}
May-be not what you have in mind, but since you didn't mention what it is for, I suppose one answer would be that you'd do it by controlling scope and program flow.
For example, you wouldn't write a game like this:
initialize player
code for level 1
...
reinitialize player
code for level 2
...
etc
Instead you'd strive for:
void play_level(level_number, level_data) {
Player player; //gets "re-initialized" at the beginning of each level using constructor
//code for level
}
void game() {
level_number = 1;
while (some_condition) {
play_level(level_number, level_data);
++level_number;
}
}
(Very rough outline to convey the idea, not meant to be remotely compilable.)
If you really must do this I strongly encourage creating a reset method for this:
class A
{
...
public:
reset() { *this= A() };
}
The above requires A to be copy and move assignable.
That is because the initial unoptimized version will copy from a temp. However copy elision may remove this step.
The behavior of A::reset() is always well defined. It replace the existing data in a valid A instance with a data from a new one. Of course any sub-class of A will still need to define its own version if you wanted its data re-initialized as well. However, failure to do so does not in and of itself invoke undefined or unspecified behavior. It simply means that only whatever memory A uses for its members will be reset. Even the involvement of virtual functions and/or virtual inheritance doesn't change this. Although the usual caveats of using such things apply.
Raw pointers will not be deleted by the above so they will need to be put into a std::shared_ptr or similar construct so the will self destruct when no longer needed.
While most answers are reinitializing an object in two steps; first, creating an initial object, and second creating another object and swapping it with the first one using placement new, this answer covers the case that you first create a pointer to an empty object and later allocate and construct it:
class c *c_instance; // Pointer to class c
c_instance = new c(arg1, ..., argn) // Allocate memory & call the proper constructor
// Use the instance e.g. c->data
delete c_instance; // Deallocate memory & call the destructor
Yes , it is possible.
If you create a method that returns a new object.
#include "iostream"
class a // initialize class
a getNewA(a object){// Create function to return new a object
a new_object(/*Enter parameters for constructor method*/);
return new_object;
}