Can you call a constructor a second time to restore a class's data members to their default values? :wave:
Printable View
Can you call a constructor a second time to restore a class's data members to their default values? :wave:
Why dont you just write a function that initializes the data members. Then you can call this function from your constructor and at any other time!
Regards,
Laitinen
No.
Create an Initialize() member function. Call it from within the
constructor and whenever you want to set the class members
to their default value.
Edit : Laitinen was faster (again).
I am not sure I understand how are you going to do it... :confused:
The obvious was to restore default values is to implement a public method in the class and move all "default" assignment from ctor to this method, then you could call this method from ctor and from any other place as well.
What the hell... you just said that I can't call a constructor twice. The purpose of a constructor in my case is to initialise some variables. But if I did what you said and called an Initialise() member function from within a constructor, that's calling a constructor twice.... think about it! *confused* I use the constructor to initialise variables, have another function that changes and messes around with those variables, then I need something to restore them back to their default. If I called a member function from within a constructor after I've left the constructor, I'm effectively calling the constructor twice?
Hi Mybowlcut!
I recommend you to read these faqs C++ Constructors
Best regards,
Laitinen
How is it called twice ? ... the constructor is only called once, so Initialize(0Quote:
Originally Posted by Mybowlcut
would only be called once from within the constructor.
Edit: OK , maybe I see what you are saying. Yes there can be an
efficiency in using assignment versus initialization lists.
constructor != initializer
The constructor can do anything you want, including initialize. I think the advise already posted here should suit your needs.
No... no no no... why would I call a function to initiliase variables when I'm in a constructor already?
create class > constructor gets called, initiliases data members and eventually finishes > call class's function from main to mess around with it's data members > call constructor to intialise values back to their default
^^ for that can I call a constructor twice (as in once automatically and once manually)? Or do I have to create a member function completely identical to a constructor to initialise values once i've left the constructor?
Yes, you have a create a member function to initialize for the second time
Thankyou, I can understand that. Thanks to everyone else who tried to explain it to me as well.
Quote:
Originally Posted by Mybowlcut
Completely identical - NO.
MYObject::MyObject()
{
Initialize();
}
MyOBject::Initialize()
{
//Variable assignments here
}
No need to create function IDENTICAL to constructor, just make your constructor to call initializer:Quote:
Originally Posted by Mybowlcut
CheersCode:class TestClass
{
private:
int a;
float b;
public:
TestClass()
{
init();
}
void init()
{
a = 42;
b = 1.0f / 13;
}
... getters/setters/messers
};
.... somewhere in your code:
TestClass obj; //contains initialized values
MessWithMyObject(obj); //change values
obj.init(); //restore values
EDIT: Doh. Late again :)
[ Redirected thread ]
Q: Can I call a constructor twice?
A: Yes, you can (although you may not).
Try this little program
Of course, the previous answers are good. I have posted that just as an aside "curiosity"... ;)Code:#include <iostream>
using namespace std;
class CFoo
{
public:
CFoo() {cout << "CFoo::CFoo - this is: " << this << endl;}
void* operator new(size_t, void* p) {return p;}
};
int main()
{
CFoo foo;
new(&foo)CFoo; // constructor called twice
return 0;
}
Could you explain this bit?
Code:CFoo foo;
new(&foo)CFoo; // constructor called twice
Lol I don't know alot of that syntax but if you say that you can call a constructor twice, and other people say you can't, then who do I listen to? Haha.Quote:
Originally Posted by ovidiucucu
Let me see if I've got this right... the order of execution will be:Quote:
Code:Completely identical - NO.
MYObject::MyObject()
{
Initialize();
}
MyOBject::Initialize()
{
//Variable assignments here
}
constructor (doesn't initiliase) > intiliase() > initiliases variables > leaves initiliase() > leaves constructor
I can't see for the life of me see the purpose of that! All it's doing is making another function do what the constructor does... and once! What I asked was if you can call a constructor twice.
So: constructor initialises variables > in a member function the variables get messed around with > constructor gets called again to initialise variables back to their default
Two people posted the same code but all it does is chuck a function into a constructor that does the constructor's job... I just don't see the point in it.
It's not that important that I find out the answer to this question, but I was just curious because it is easier than creating another function to initiliase a class's variables a second time.
Edit: Why is this in Non-Visual C++? I'm using VS.
That code posted by Ovidiu uses the placement new operator. But that can be disastrous and it is probably undefined behaviour by the standards. You should not be doing that and that is what Ovidiu tells when he say "(although you may not)."
Hobson's post illustrates how you would do it.. but you may want to change the init call from the constructor to actual initialization in the initializer list. It would suffer from a problem though, every time a new data member is added to the class - you would need to make changes at atleast 2 places - the constructor and the init() function while with Hobson's way you would need to do it at one place only.
init() can be overloaded as well to have different set of assignments. Also, it would be better to call this function reset() (more meaningful to me) but it really is your choice.
In fact forget about calling twice, you cannot call the constructor explicitly even once (except for using the placement new syntax but that is not what you are doing).
Do you anywhere see that you are even calling the constructor once? Let me know where... It is being called automatically upon creation of the object. So, what is being told to you is that the constructor gets called only when the object is being constructed. Never again. With the member function init() what you are doing is delegating the initialization to the init function. The members of the class that Hobson has used are POD types and hence their initialization doesn't happen by default in the constructor - they remain uninitialized. The init function does that. init() is just another member function. You can call it from anywhere - the constructor, destructor, any other member function of the class or from user code using the object of that class. So, what is being done the second time is just that the member variables are being set to the mentioned values. The constructor is not being called.
If it helps you can imagine the second call to init() as being 2 setter functions that are being called to set each of the two member variables.
How that looks like a constructor call to you is unimaginable by me! Again, as I said earlier, forget about calling the constructor twice, you don't even call it once yourself!
So you can't call a constructor full stop? Thanks. And if I wanted to intialise variables I'd have to create a separate function? That's all I wanted to know.
Edit: The thing that I still don't understand though, is why 2 people would suggest to call a intialise function from within a constructor...
That is because you wanted to be able to "reset" the object to the state it had when you constructed it. Easiest way to do this is like Hobson showed you!Quote:
Originally Posted by Mybowlcut
Regards,
Laitinen
There is a rule which says something like: Each logical task shoud be performed in dedicated function. And each function should perform only one logical task. In your case, this logical task is to set members to theirs initial state. This task is to be performed more than once, not only at the beginning of the object lifetime. So just create ONE function (called reset or init or whatever) and call it when appropriate. You do not have to call this function inside of constructor, if you really do not want to. You may call it later, when object is already constructed:
But in such a case you might to forget (or miss from any else reason) to call initializer. If initialization would be performed only once, you'd be able to set values to members in constructor initialization list (again, not in constructor itself!).Code:CFoo foo;
.... some code, and later
foo.init();
I think that you just misunderstood the meaning of constructor. Constructor is NOT an initializer. It may be, but it does not have to. Sometimes it is even impossible to initialize an object inside of constructor, thats how all MFC works: you always have to call CWnd::Create after creating CWnd object.
The reason why I did not use initializer list in my example is that because I think it would be pretty useless to create two different snippets of code with the same functionality. At least in this case.
You also could to completely recreate your object, but that not always would be good:
Above has a drawback that it creates completely new CFoo object and there is no way to reinitialize only some members, and keep some others unchanged.Code:CFoo foo; //call constructor for the first time ;)
MessWithMyFoo(foo);
foo = CFoo(); //init foo with brand new CFoo, almost by calling ctor second time (pun indented)
I am sorry, but I do not know how to say it more clearly.
Cheers,
Hob
I also cannon understand why only 2...? :confused:Quote:
Originally Posted by Mybowlcut
Or you cannot count?! :wave: :rolleyes:
All people in this thread (except you) suggested the same - implement the additional method called initialize or init or reset or whatsever ... serving for your purpose - set the default valuesf or the class object!
There is no full stop. You did not understand. Probably you need to read up on constructors a little bit and my posts again.
Initialization happens in constructors but you do not call the constructors. When you declare an object it is called automatically and not explicitly by you. Now, constructors are the place where initialization happens - you can leave the initialization empty - in which POD are uninitialized and non-POD are default initialized. You can write initialization code in the initializer list. You can write code in constructor body (but that is not initialization, that is assignment) and you can take that all code in another function and call that function from the constructor.
I don't understand what you are not understanding, or where you are confusing. Can you post some code upon your understanding or misunderstanding that we can say is right or wrong and then may be you can conclude?
Ovidiu's "curiosity" just made my teeh grind... :D "Curiosities" like this one are nasty thing, harmless for poster, and make their readers fat :no-no-handshoe:
Hobson you said it very clearly. Everyone has been very patient but exterminator has given me an idea, so:
Ok. I was just interested to know if this would ever work and if it does, if it's bad programming practice.Code:class Test
{
public:
Test(); //constructor
void mess();
private:
int a;
int b;
}
Test::Test(): a(0), b(0) {} //initialise private data members a and b to 0
void Test::mess()
{
a = 1; // mess around with data members
b = 1;
}
int main()
{
Test myTest; //constructor is called
myTest.mess(); //change variables
myTest.Test(); //constructor called again to intialise values back to original
return 0;
}
No, it is not possible.
Things which are possible to say:
- "Look, this line creates new local object, and this causes constructor to be executed!"
- "Look, I created object with operator new, and constructor was executed!"
- "Yay, when I am creating a temporary object, ctor runs!"
You know that someone is a nasty liar, when he says:
- "I just called a constructor [explicitly] for this object!"
Like exterminator said, there is no way to call ctor explicitly. By 'no' I mean very no. Ctor is called implicitly when new objct is created, in any manner: local, globa, static, temporary, new, placement new. But no creation - no ctor call.
Cheers
It just won't (at least, it should NOT) be compiled!Quote:
Originally Posted by Mybowlcut
My VC++ 6 compiler displays:Quote:
error C2274: 'function-style cast' : illegal as right side of '.' operator
To summarize:
1) the constructor can not "be called" twice (technically
not even once). (Constructors do not have names and you
can not take the address of the constructor).
2) What Ovidiu did was create a SECOND object (but at the
same location as the first). So TWO objects are created,
but only ONE destructor will be called. Run the following
code and watch the memory (using task manager/top).
3) You can use the following to create a new object on top ofCode:#include <string>
class CFoo
{
public:
CFoo() : s("Hello World") {}
void* operator new(size_t, void* p) {return p;}
std::string s;
};
int main()
{
CFoo foo;
// when you want to "reinitialize"
while (true)
{
new (&foo) CFoo;
}
return 0;
}
the old one, without the memory leak (assuming the alignment
of the char array is compatible with the alignment for a CFoo
object).
Code:#include <string>
class CFoo
{
public:
CFoo() : s("Hello World") {}
void* operator new(size_t, void* p) {return p;}
std::string s;
};
int main()
{
char memory_pool[ sizeof(CFoo) ];
CFoo * pFoo = new (memory_pool) CFoo;
// use pFoo ...
// when you want to "reinitialize"
while (true)
{
pFoo->CFoo::~CFoo(); // destroy old object
pFoo = new (memory_pool) CFoo; // create a new object
}
// if the loop was such that you could exit from it, you
// would need to call the destructor if not already done.
return 0;
}
One or two more posts about placement new and I bet that very soon we will read about some production code nonsensically using it at www.TheDailyWTF.com :D
Case closed! My question has been answered! Thanks guys. :)
BTW anything involving new I don't understand sorry to say.
ONLY if CFoo has a well formed assignment operator :eek:Quote:
foo = CFoo(); //init foo with brand new CFoo, almost by calling ctor second time
It makes a difference.Quote:
I can't see for the life of me see the purpose of that! All it's doing is making another function do what the constructor does... and once! What I asked was if you can call a constructor twice.
A constructor is NOT a normal member function. It's specially handled by the compiler, and implicitly does a lot of things under the hood, especially when inheritance is involved, moreover it has specific semantics so that when new() is called, the storage gets a new effective type.
Do you know the difference between initialization and assignment?Quote:
Two people posted the same code but all it does is chuck a function into a constructor that does the constructor's job... I just don't see the point in it.
You're going to get into troubles if you do that!
For example, if your class contains a std::string member, I can claim that with most compilers, the second initialization won't free the memory of the first string, and it'll do a memory leak!
If you're lazy to such an extent, I guess you don't write many "secondary functions", but write huge functions... That would be a very bad programming style.Quote:
It's not that important that I find out the answer to this question, but I was just curious because it is easier than creating another function to initiliase a class's
No, behavior is defined, but this is evil, and may certainly create memory leaks!Quote:
Originally Posted by exterminator
Quote:
Originally Posted by basic.life
You can indirectly, through placement operator new, but this is evil and will produce memory leak. Bad idea.Quote:
Originally Posted by Mybowlcut
Actually, this is "re-using" the memory of the previous object. The old object dies (and memory is likely to leak) while a new object takes its place.
Very good.Quote:
Originally Posted by Hobson
This basic principle of procedural programming must not be forgotten in OOP, because OOP is an extension of the procedural programming paradigm and must keep the good principles.
I would like to tell, so that it becomes clear to everybody, that even when not using the initializer list, constructors of members (and base classes) are implicitly called before the "body" of the constructor is entered.Quote:
Originally Posted by exterminator
Exactly! And this is the reason why we cannot do explicit instantiation of constructor templates! Here - http://learningcppisfun.blogspot.com...-explicit.htmlQuote:
Originally Posted by Philip Nicoletti
It's like saying somebody can be born twice and be the same (like in my example) or may be qite different (like in your extension).Quote:
Originally Posted by Philip Nicoletti
Now returning to good programming common sense, each of us would be happy to have an Init() method when the destructor is approaching (like the OP purpose and the solution offered here)... :)
Ovidiu
PS. I have heard that every cat has nine constructors. :D ;)
not really. ONLY if there is dynamic allocation in the assigned class AND if CFoo has a assignment operator. there is std::string used so its safe to let the compiler generate a assignment operatorQuote:
Originally Posted by TheCPUWizard
so if he dies from age he can live 9 times his age? or will it create a gaia leak in the planet?Quote:
Originally Posted by ovidiucucu
Mitsukai,Quote:
Originally Posted by Mitsukai
If there is no dynamic allocation, and all member variables have fell formed assignment operators, then the default assignment operator will be a well formed assignment operator. Therefore I stand by my original statement.