class T
{
public:
int m_i ;
T () { m_i = 1 ; }
T(int k ) { T() ; }
};
int main()
{
T t(0 );
cout<< t.m_i <<endl;
return 0;
}
When i invoke a constructor funciton within another constructor funciton , this constructor will not impact on this object .
In the above sample code , The t.m_i will remain uninitialize . why
? i test it in VC6.
I have gone throught the ISO C++ specificaiton , but no any thread was been found .
Mikey
November 30th, 2002, 01:35 PM
You shouldn't call another constructor inside a constructor but a reset-function in both:class T
{
public:
int m_i ;
T () { reset() ; }
T(int k ) { reset(); }
private:
void reset(){m_i = 1 ;}
};
(And just for design: You shouldn't put variables in the public-section, but implement get/set-functions for that purpose.)
Mikey
Mikey
November 30th, 2002, 01:46 PM
(But to Your question: I really do not know, why m_i stays uninitilized. Maybe because it's not legal to call a constructor directly.)
Mikey
Andreas Masur
November 30th, 2002, 01:47 PM
Originally posted by flysnow
When i invoke a constructor funciton within another constructor funciton , this constructor will not impact on this object .
In the above sample code , The t.m_i will remain uninitialize . why
? i test it in VC6.
The reason is quite simple...the call to the first constructor inside your second one will create a temporar instance of 'T' which is only valid for the current scope thus only until the second constructor returns...
You can easily see what happens while debugging through the construction of the instance of 'T'...take a look at the 'this' pointers...the following code demonstrates the problem as well...just run it and look at the output...
int main()
{
{
T t(0);
std::cout << "Instance created" << std::endl;
}
return 0;
}
flysnow
December 1st, 2002, 08:51 AM
I know the result , but why? why was the temporary object created ?
Is it a normal behavior defined by C++ specificaiton ?
Thanks Mikey and Andreas Masur .
The code is just for describing the problem . so i put the m_i public. :)
Mikey
December 1st, 2002, 09:26 AM
I know the result , but why? why was the temporary object created ?
Andreas is absolutely right, that You create a temporary object instead of calling Your own default-constructor.
It's really quite simple:
You create an object of T with T() (default-ctor). It doesn't matter if You write this inside or outside Your class.
You can prove this by comment out Your default-ctor-definition:class T
{
public:
int m_i ;
// T () { m_i = 1 ; } no default-constructor!
T(int k ) { T() ; } // try to create a T-object through the default-ctor
};
int main()
{
T(); // the same: creating a T-object through default-ctor
T t(0 );
cout<< t.m_i <<endl;
return 0;
}
this raises the error:
... error C2512: 'T::T' : no appropriate default constructor
This is standard C++-behaviour
Mikey
flysnow
December 1st, 2002, 10:57 AM
Mikey:
Thanks!
Can I called a constructor funciton directly to create a object ?
The answer is Yes by your sample code .
but why the C++ need this feature ? Because you can not access this temporary object by any way.
Mikey
December 1st, 2002, 11:08 AM
You can create an object, without saving it to a var, if You only need a constructor-execution:
class T
{
public:
T()
{
OutputDebugString("i was called, to do some work!\n");
}
};
int main()
{
T(); // output ctor-text
return 0;
}
Output:
i was called, to do some work
But there are very rare cases, where this makes sense
Mikey
flysnow
December 1st, 2002, 11:18 AM
Mikey :
Thanks very much :)
If you want to do it like what you mentioned , why don't use a stactic function or a globle function ? A instantiation of object is very costly.
I just want to know the roof cause :)
Mikey
December 1st, 2002, 11:26 AM
Originally posted by flysnow
If you want to do it like what you mentioned , why don't use a stactic function or a globle function ? A instantiation of object is very costly.
Yes, of course a static function or whatever would be better.
As I said, there are very rare cases for the need of an object without var. (And currently I can't imaging one :D)
It was just an example, how You can use it.
Mikey
Mikey
December 1st, 2002, 11:35 AM
A useful case would be to return it from a function:
CString getString(LPCSTR sz)
{
// create 2 temp. objects (return the first one)
return CString(CString(sz)/*temp. obj to use the '+'-operator*/ + "hello");
}
CString cs = getString("hi and "); // cs="hi and hello"
Mikey
flysnow
December 1st, 2002, 11:38 AM
Mikey :
Do you know who is the most famous expert in this C++ board ? I think only the C++ expert can answer this questin .
Mikey
December 1st, 2002, 11:42 AM
I think Your question was already answered some mails ago...
Mikey
flysnow
December 1st, 2002, 11:51 AM
Originally posted by Mikey
A useful case would be to return it from a function:
CString getString(LPCSTR sz)
{
// create 2 temp. objects (return the first one)
return CString(CString(sz)/*temp. obj to use the '+'-operator*/ + "hello");
}
CString cs = getString("hi and "); // cs="hi and hello"
Mikey
But I think it isn't the exact explanation for my question , If you traced the assemble code of my sampe code in VC , you will find that a destuctor function was called immediately after construtor function was called on the temporary object .
So I don't think it can return a object by that way .
Mikey
December 1st, 2002, 12:09 PM
Since You don't save Your object in a var, it's destroyed after use.
Mikey
December 1st, 2002, 12:56 PM
Originally posted by flysnow
So I don't think it can return a object by that way .
Yes, it can - try the code if not believing... ;)
Mikey
flysnow
December 1st, 2002, 01:37 PM
Mikey :
I think you are right .
"So I don't think it can return a object by that way . " I just say
Yes , it can return a object , but it doesn't use constructor directly to create temporary object .
now I belive it use constructor directly to create temporary object .
you are right . Thanks very much .
flysnow
December 1st, 2002, 11:01 PM
Mikey:
I found some evidences that your explanation had some problems.
Because if you return a object in a function , It use the copy constructor funciton to create this object instead of constructor function .
You can try the following code . so why we need a constructor function to create a temporary object is still a quetion .
Who can give me answer ?
#include "iostream"
using namespace std;
class T
{
public:
T() { cout<< " T constructed " <<endl ; }
~T(){ cout<< " T destructed " <<endl ; }
T( const T & )
{
cout <<" copy structor " <<endl;
}
T & operator = ( T & t ) { cout << " operator = " <<endl ; return *this; }
T GetSame() { return *this ; } //this function only call the copy constructor function instead of constructor to create a temporary object .
};
int main(int argc, char* argv[])
{
T t1;
T t2;
t2= t1.GetSame();
return 0 ;
}
Andreas Masur
December 1st, 2002, 11:23 PM
Originally posted by flysnow
int main(int argc, char* argv[])
{
T t1;
T t2;
t2= t1.GetSame();
return 0 ;
}
I think there is some misunderstanding of the basic concepts...
Constructors are called when an instance of a class needs to be constructed without being assigned or returned or anything else...
In all the other cases the copy constructor or the assigment operator will be called...thus
int main(int argc, char* argv[])
{
T t1; // Constructor
T t2; // Constructor
The copy-constructor is called because both instances ('t1' and 't2') are already constructed. Therefore one instance just needs to be copied...
flysnow
December 2nd, 2002, 12:49 AM
Originally posted by Andreas Masur
I think there is some misunderstanding of the basic concepts...
Constructors are called when an instance of a class needs to be constructed without being assigned or returned or anything else...
The copy-constructor is called because both instances ('t1' and 't2') are already constructed. Therefore one instance just needs to be copied...
yes ,but I returned a object in a funciton , it should create a temporary object on stack. because return object is passed by value instead of by reference .
Does it make sence ?
flysnow
December 2nd, 2002, 01:02 AM
Originally posted by Andreas Masur
int main(int argc, char* argv[])
{
T t1; // Constructor
T t2; // Constructor
The copy-constructor is called because both instances ('t1' and 't2') are already constructed. Therefore one instance just needs to be copied...
Andreas :
As per your explanation , It doesn't need to invoke the copy constructor , because it 's enough to invoke operator = .
t2= t1.GetSame();
but infact , this statement called the copy constructor first ,and then call = operator = funciton .
galathaea
December 2nd, 2002, 03:46 AM
** galathaea's thoughts on reading :
This is getting a little scattered, so let's try to focus on the points being made and try to understand what confusion is happening here. It could be mine, but...
ClassName();
creates what is known as an anonymous instance of the class. This is a common idiom that does not need anymore expert advice than what has been given (Andreas and Mikey are two of the smartest posters here on CodeGuru in my opinion...). One common use is in a form of object factory (not common today, but at one point it was used rather widespread) where one creates symbol classes, ie. classes that have a name only (no members, basically a string precompiled into a more efficient form) as the overloaded parameter to decide which factory function to call.
Now a destructor gets called on every object created. So it depends on what objects are created. One can return a temporary object that then gets assigned into a given variable, something like
MyObject = MyFunc(...);
or copied
MyClassType MyObject(MyFunc(...));
or
MyClassType MyObject = MyFunc(...);
but either way, the destructor is fired when the temp object finishes the sequence point it is attached to. So it is not only possible but quite easy for the temp object to last long enough for the copy or assignment, but no longer.
Any anonymous temporary object is not found in the same logical memory as the instantiated objects of the full code block (the c++ "stack", not necessarily related to a computers execution stack, though I know of no case where they are different). Instead, logically to the compiler, it exists only for the duration of the sequence points it encompasses. Everything else occurs through argument passing steps, which invoke copies or references. These argument passing steps may be of whatever function is called attached to the relevant sequence points, including operator=.
At least, this is how I understand things. If I err, there are plenty intelligent posters on these boards that will clean up my language...
Gabriel Fleseriu
December 2nd, 2002, 04:14 AM
In addition to what has been said:
There are obvious cases where a temporary created object could be eliminated by the compiler as an optimization. An example is:
void g(T t)
{
/*...*/
}
void f(T t){
g(t);
}
int main(){
T t;
f(t);
return 0;
}
The compiler had enough information to see that f() only calls g(), and that it does not need to create one copy of 't' to pass it to f() and another copy-of-the-copy to pass it to g(). This indeed was a legal optimization until the last amendment of the Standard. However, this is not a legal optimization for a compiler any more. The only situation where a compiler is allowed to bypass the creation of a temporary object is the optimization of the return statements.
In your example:
t2= t1.GetSame();
the compiler could otimize away the creation of the temp value -- but it is not oblidged to do so. If it doesn't, a temp variable is created with the copy-ctor and the operator = is invoked with the temp variable as rhs.
I didn't try to compile the code in release mode with full optimization -- but it would be interesting what the compiler makes out of it.
Note that against the naïve assumptions, following code:
T t1;
T t2 = t1;
calls the copy ctor when creating t2 -- and not the operator =, despite there being a "=" sign in that statement.
flysnow
December 2nd, 2002, 04:34 AM
Originally posted by galathaea
creates what is known as an anonymous instance of the class. This is a common idiom that does not need anymore expert advice than what has been given (Andreas and Mikey are two of the smartest posters here on CodeGuru in my opinion...).
Yes , it will create anonymous instance .. but what we is discussing is why C++ need this feature ? when this feature can be use ?and why don't need scope like T::T() when you call the construtor ?
If a global funciton name is the same name with class T, Global function will be called instead of the class construtor function . This is a strange behavior .
One common use is in a form of object factory (not common today, but at one point it was used rather widespread) where one creates symbol classes, ie. classes that have a name only (no members, basically a string precompiled into a more efficient form) as the overloaded parameter to decide which factory function to call.
I am not very clear about what you said . Can you explain it more detai? Thanks in advance .
galathaea
December 2nd, 2002, 05:16 AM
Here's an example from C++ for Real Programmers by Jeff Algers (proper props). This is to place the idiom in someone else's hands and defer questions of authority away from my timid self...
class VariationDad {};
class VariationAuntieEm {};
class Grandpa {
public:
static Grandpa* make(VariationDad);
static Grandpa* make(VariationAuntiEm);
};
// In your program
Grandpa* g = Grandpa::make(VariationDad());
Its a really simple example in my opinion, and not necessarily the best option in most cases, but it generally shows one of the several reasons for a temporary object. Basically here you make a temporary VariationDad to give purely the type to distinguish which overloaded function to call. It was one of the first steps towards the major generic object factory idioms of today. Temporary object are also useful for many other cases of the general grammatical need: pass an argument to a function that generically determines the operation of the function, but this argument never needs to be referred to again outside the function block.
Also, as mentioned before, this is a preferred meaning because design is worsened when one attempts to call one ctor from another (or anywhere else, for that matter). There should be a logical separation from construction-form dependent work and general object initialization, and it is best if this is represented in the class method structure. The question of why c++ implements the call to what would appear to be a ctor that way is thus: because it adds to the functionality of the language, whereas the naive ctor call would add nothing to the language that could not be accomplished by just adding an Initialize() method.
flysnow
December 2nd, 2002, 06:08 AM
Originally posted by Gabriel Fleseriu
In addition to what has been said:
There are obvious cases where a temporary created object could be eliminated by the compiler as an optimization. An example is:
void g(T t)
{
/*...*/
}
void f(T t){
g(t);
}
int main(){
T t;
f(t);
return 0;
}
The compiler had enough information to see that f() only calls g(), and that it does not need to create one copy of 't' to pass it to f() and another copy-of-the-copy to pass it to g(). This indeed was a legal optimization until the last amendment of the Standard. However, this is not a legal optimization for a compiler any more. The only situation where a compiler is allowed to bypass the creation of a temporary object is the optimization of the return statements.
I disagree your opinion though you are an expert :)
The compiler can not optimize the code in this situation. because
the function g() may change the t ( parameter ) value . and because you pass the t by value ,so it can not impact on outside variable t .
so I think the compiler should create a copy -of the -copy to pass it to g(). otherwize you will change the value of outside variable t .
i
Gabriel Fleseriu
December 2nd, 2002, 06:43 AM
Originally posted by flysnow
I disagree your opinion though you are an expert :)
The compiler can not optimize the code in this situation. because
the function g() may change the t ( parameter ) value . and because you pass the t by value ,so it can not impact on outside variable t .
so I think the compiler should create a copy -of the -copy to pass it to g(). otherwize you will change the value of outside variable t .
i
In this particular case, the compiler actually could optimize away one of the two copies. Think of it like this: f() does nothing with the copy it gets, except that it calls g(). So why create another copy just for g() to use?
This reasoning doesn't hold on the general case because ctors can have side effects (like setting a lock or so) and the number of objects created must be predictable.
The issue is described in great detail in Herb Sutter's "Exceptional C++". Herb also touches the issue here (http://www.gotw.ca/gotw/036.htm)
flysnow
December 3rd, 2002, 12:50 AM
OK , I see .
Thank all of you for your zealous help :)
AnthonyMai
December 3rd, 2002, 08:35 AM
Believe it or not, you can actually call one constructor from within another constructor. Who would want that? I don't know. But you can do it if you really want to.
Constructors are just like other class member functions. It has a hiden "this" pointer. The problem that people don't usually explicitly call a constructor like a regular function call is, the object hasn't been constructed yet before the constructor, so you wouldn't have a object pointer to be used for the call to the constructor.
But in the case of one constructor call another constructor, we already have a this pointer. So the way to do it is like this:
class T
{
public:
int m_i ;
T () { m_i = 1 ; }
T(int k ) { this->T::T(); }
};
Yes it works. You can even add some none-trivial class members like std::string and they will be constructed and then re-constructed, without being destroyed first before re-construction.
Elrond
December 3rd, 2002, 09:47 AM
Originally posted by flysnow
Andreas :
As per your explanation , It doesn't need to invoke the copy constructor , because it 's enough to invoke operator = .
t2= t1.GetSame();
but infact , this statement called the copy constructor first ,and then call = operator = funciton .
To come back to a previous post, the reason why it calls the copy constructor first is because of the signature of the GetSame function:
T GetSame(){return *this;}
This means that the function returns a temporary object. This temporary object is created here using the copy operator with *this as parameter.
Then it is copied to t2 (using the copy operator).
If you want to prevent this call to the copy constructor you should have:
const T& GetSame(){return *this;}
flysnow
December 3rd, 2002, 12:33 PM
Originally posted by AnthonyMai
class T
{
public:
int m_i ;
T () { m_i = 1 ; }
T(int k ) { this->T::T(); }
};
Yes it works. You can even add some none-trivial class members like std::string and they will be constructed and then re-constructed, without being destroyed first before re-construction.
I don't think so . you can check if the variable m_i will is 1 when you create object like T t(2);
I have found the answer from ARM. you can call a constructor with another constructor , but it's useless.
PaulWendt
December 3rd, 2002, 12:43 PM
[QUOTE]Originally posted by flysnow
Edit: Totally misguided post. Mai's code may work, but your
mileage may vary depending on your compiler.
Edit: Oh, and the ARM is dated in some areas as it was written
years before the standard was finalized. It does give some
valuable insights, but it can't be taken as gospel in all places.
AnthonyMai
December 3rd, 2002, 02:43 PM
Yes it works. You can even add some none-trivial class members like std::string and they will be constructed and then re-constructed, without being destroyed first before re-construction.
I don't think so . you can check if the variable m_i will is 1 when you create object like T t(2);
I have found the answer from ARM. you can call a constructor with another constructor , but it's useless.
Whether you think so or not is only irrelevant to whether you understand it or not, but not to whether it is actually true or not. The fact is it really works. However I did state in my message that I don't know how some one would find it useful. I personally never needed to do that, but since the OP asked for how to call constructor from constructor, so you get what you asked for.
Any thing is possible.
PaulWendt
December 3rd, 2002, 03:30 PM
As I alluded to before, this might not work on your compiler. For
example, Mai's trick does not work on gcc-3.1.1. I get the
following compile-time error:
c++ str_block.cpp -c
str_block.cpp: In constructor `T::T(int)':
str_block.cpp:15: parse error before `;' token
make: 1254-004 The error code from the last command is 1.
I toyed around with the this->T::T() part of the program and I was
able to get it to compile, but T() was never called [m_i printed out
as garbage on Visual Studio, but 0 on one of my gcc systems].
Thus, use Mai's trick only if you want to enter the uncharted
realm of unportability.
--Paul
Paul McKenzie
December 3rd, 2002, 05:59 PM
Originally posted by PaulWendt
As I alluded to before, this might not work on your compiler. For
example, Mai's trick does not work on gcc-3.1.1. I get the
following compile-time error:
I toyed around with the this->T::T() part of the program and I was
able to get it to compile, but T() was never called [m_i printed out
as garbage on Visual Studio, but 0 on one of my gcc systems].
Thus, use Mai's trick only if you want to enter the uncharted
realm of unportability.
--Paul On the Borland C++ Builder 6.0, you get this error:
'T is not a member of 'T'. On the Comeau compiler, you get this:
ComeauTest.c", line 6: error: a constructor or destructor may not have its address
taken
T(int k ) { this->T::T(); }
^
From the ANSI standard 12.1.12:
No return type (not even void) shall be specified for a constructor. A return statement in the body of a
constructor shall not specify a return value. The address of a constructor shall not be taken.
Regards,
Paul McKenzie
AnthonyMai
December 3rd, 2002, 07:20 PM
Hey its not my invention to call constructor that way. I actually learned it from CodeGuru.
No return type (not even void) shall be specified for a constructor. A return statement in the body of a
constructor shall not specify a return value. The address of a constructor shall not be taken.
The address of a constructor shall not be taken by WHO Obviously some one has to take the address of the constructor and actually make the call, or else how would it magically end up jumping into the constructor code.
The address of a constructor is taken at least by one outlaw, the new operator. Actually by two, since the compiler can take the address and call constructor to initialize an object on the stack, too.
Here is the another trick how to call constructor from a constructor:
T::T(int k )
{
new(this) T();
}
But really, this->T::T(); would be simpler when compiled and the effect is the same.
PaulWendt
December 3rd, 2002, 08:49 PM
Originally posted by AnthonyMai
But really, this->T::T(); would be simpler when compiled and the effect is the same.
Assuming your compiler is Visual Studio, then you're right. If you
use any other compiler out there, don't count on it :)
--Paul
codeguru.com
Copyright Internet.com Inc., All Rights Reserved.