[Okta Webinar] Learn how to a build a cloud-first strategyRegister Now

x
  • Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 2164
  • Last Modified:

Can I call member functions inside a constructor function ?

I often declare/define an Empty() member function for my classes, to make sure it's in a known
state with all held resources released.

I call this Empty() member in my constructors and destructors and throughout the program.

However, I've been recently experiencing weird GPFs, programs just exiting abruptly, and pointer-incrementing not working correctly (!). These faults were eventually traced to having the Empty() call in my constructors; removing the Empty() call (or making it an inline) made the program work correctly.

I'm aware that a general Empty() won't work inside a constructor because if you have something like:
if (ptr!=NULL) free(ptr) inside your Empty() and that ptr (member of MyClass) is set to a random value by the time the constructor is called, freeing it is a bit silly.

However, I am very careful to make sure that I initialise all such pointers that will be used by the Empty() as NULL in the constructor before the Empty() is called. nevertheless, I stil get weird happenings.

Is this an MFC-specific thing, or should I generally never use member functions inside constructors, on the basis that the object isn't fully constructed yet ?

If so, what's the best strategy for non-duplication of code between the "construct" and "empty" functions when you have a lot of member variables that need to be initialised ? Having to write out what amounts to the same code in the two cases is a bit excesive.


Richard [in SG1]
CMyClass
{
public:
  CMyClass();
  ~CMyClass();
  void Empty();
private:
  // arbitrary data members
};
 
CMyClass::CMyClass()
{
  // .. Set various resource holders to NULL.f
  Empty();
}
 
CMyClass::~CMyClass()
{
  Empty();
}
 
void CMyClass::Empty()
{
  // release resources.
}

Open in new window

0
muttley3141
Asked:
muttley3141
  • 3
  • 3
2 Solutions
 
jkrCommented:
In general, that setup is common and should lso work fine. The above code snippet unforunately does not show any pitfalls, since it is mostly "academic". I'd rather just run your code under a debugger and isolate the issues.
0
 
muttley3141Author Commented:
OK. I'll try and rebuild my code to demonstrate the problem. I'll do that tomorrow.
0
 
evilrixSenior Software Engineer (Avast)Commented:
>> should I generally never use member functions inside constructors, on the basis that the object isn't fully constructed yet ?
With the exception of virtual functions it is perfectly safe to call class member functions from a constructor. Virtual functions are different because the v-table isn't fully created until the constructor call is complete. This being the case you will not get polymorphism, the function called will always be in the context of the static and not the dynamic type. This is rarely what you want.

http://www.artima.com/cppsource/nevercall.html

Class member functions are just functions that take an implicit 'this' pointer as an invisible first parameter. The functions themselves exist even if a class instance doesn't and you can even take their address. You can then later call the function by 'binding' it to a this pointer of any object of that class.

As jkr as stated, it would be better if you could post code that reproduced the problem.

I hope this info helped.

-Rx.
#include <iostream>
 
class foo
{
public:
	void bar() { std::cout << "Hello" << std::endl; }
};
 
int main()
{
	// Create a function pointer call bar_fp and assing address of
	// member function bar of class foo (no instance exists yet!)
	void (foo::*bar_fp)() = &foo::bar;
 
	// Now create an instance of foo
	foo f;
 
	// Now bind instance f to the function pointer defined above
	// and call it.
 
	(f.*bar_fp)();
}

Open in new window

0
Industry Leaders: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

 
muttley3141Author Commented:
evilrix wrote this:

> With the exception of virtual functions it is perfectly safe .....

Ah. Maybe it was a virtual function where I was trying to call an Empty() from inside a constructor.

It'l take me some time to get sample code ready (my subversion server is down !). I didn't post it originally because I was expecting a plain "you can't do that" or "the VC++6.0 compiler is buggy in that respect".

I hadn't thought about the virtual-ness of the functions at the time.
0
 
evilrixSenior Software Engineer (Avast)Commented:
Hi Muttley3141.

Did you get to the bottom of this in the end? Hopefully our answers helped, but I'd like to be sure we did solve your problem. Was you calling a virtual function? Was it caused by something else? I'm just curious as I hate not finding out the solution to a riddle :)

Cheers.

-Rx.
0
 
muttley3141Author Commented:
Well, no, I didn't really get to the bottom of things. I found out that it wasn't a virtual function in question, but a templated one. Templates confuse me and I had to re-do it for other reasons anyway.

Due to the size of the code, I can't really isolate the bit which is causing the problem, so I had to rewrite things.

The basic problem was that I had implemented a "list" class of my own but whenever I called a "Remove(i)" operation on it, the program GPFed. I found then that it worked perfectly if I put my Empty() function's contents, unrolled, inside the constructor, so that the Empty()er and the constructor were effectively running the same code. This is what made me think that putting calls to members inside a constructor was verboten.

I don't know much about templates and try to avoid them, but I do know that they are implemented in a manner similar to textual substitution and not in a manner similar to C++ polymorphism.

So, I still don't know what's going on here.



0
 
evilrixSenior Software Engineer (Avast)Commented:
>> I don't know much about templates and try to avoid them
Templates are fantastic... I love them :) You can do so many cool things with templates, seriously try and embrace them, they can make writing c++ code so much simpler once you get the hang of them

The following is a good link about template basics
http://www.cplusplus.com/doc/tutorial/templates.html

>> but I do know that they are implemented in a manner similar to textual substitution
Not really. The difference between templates and #define's (which really are text substitution) is that templates are instantiated (that's what we call it when the compiler injects the templates code) by the compiler, and they are first class C++ constructs and fully obey all the rules of C++.

I suspect the problem isn't so much because the code is templated but; rather, the compiler is generating code that you didn't expect.

>> and not in a manner similar to C++ polymorphism.
Templates are, in fact, a form of polymorphism. The difference is the polymorphism you refer to is runtime polymorphism provided by the late-binding mechanism, which we call dynamic polymorphism. Templates (and function overloading) and a form of static polymorphism, which is resolved by the compiler and compile time. See example, below.

If you' like to get to the bottom of this (and it is usually a good idea to try and understand a problem because otherwise you can't be sure you've actually fixed it... maybe you've just hidden it and at some point it'll come back and bite you) I'd be more than happy to look at a sample of the original code to see if I can spot where it's going wrong.


#include <iostream>
 
enum OUTPUT_TYPE
{
	OUTPUT_FOO,
	OUTPUT_BAR
};
 
template <OUTPUT_TYPE>
class outputterT;
 
template <>
class outputterT<OUTPUT_FOO>
{
public:
	void operator()() const
	{
		std::cout << "foo" << std::endl;
	}
};
 
template <>
class outputterT<OUTPUT_BAR>
{
public:
	void operator()() const
	{
		std::cout << "bar" << std::endl;
	}
};
 
typedef outputterT<OUTPUT_FOO> outputterFoo;
typedef outputterT<OUTPUT_BAR> outputterBar;
 
template <typename OUTPUT_TYPE OT>
void Output(outputterT<OT> const & outputterConcept)
{
	outputterConcept();
}
 
int main(int argc, char* argv[])
{
	outputterFoo foo; // Output concept for foo
	outputterBar bar; // Output concept for bar
 
	// Static polymorphism in action
	Output(foo);
	Output(bar);
}

Open in new window

0

Featured Post

Concerto Cloud for Software Providers & ISVs

Can Concerto Cloud Services help you focus on evolving your application offerings, while delivering the best cloud experience to your customers? From DevOps to revenue models and customer support, the answer is yes!

Learn how Concerto can help you.

  • 3
  • 3
Tackle projects and never again get stuck behind a technical roadblock.
Join Now