Sign in to follow this  

Constructor not called if a default param is supplied?

This topic is 4558 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Ok, my question is simple: is the constructor for a class not called if it has a default parameter? I have a class:
namespace dftCommon
{
    class StateMachine
    {
        Value*            m_pStates;
        unsigned int    m_nCount;
    public:
        StateMachine(unsigned int nStateCount = 16); // Fixed
        ~StateMachine();
        
        void    SetState(unsigned int nIndex, Value NewState);
        Value    GetState(unsigned int nIndex);
        void    SaveStates(Value* pStates, unsigned int nCount);
        void    LoadStates(const Value* pStates, unsigned int nCount);
    };
}



dftCommon::StateMachine::StateMachine(unsigned int nStateCount)
{
    assert(nStateCount > 1);
    m_pStates    = new Value[nStateCount];
    m_nCount    = nStateCount;
    memset(&m_pStates, 0, nStateCount);
}

dftCommon::StateMachine::~StateMachine()
{
    delete m_pStates;
    m_nCount = 0;
}

void dftCommon::StateMachine::SetState(unsigned int nIndex, Value NewState)
{
    assert(nIndex < m_nCount);
    m_pStates[nIndex] = NewState;
}

dftCommon::Value dftCommon::StateMachine::GetState(unsigned int nIndex)
{
    assert(nIndex < m_nCount);
    return m_pStates[nIndex];
    return 0;
}

void dftCommon::StateMachine::SaveStates(dftCommon::Value* pStates, unsigned int nCount)
{
    assert(pStates != 0);
    
    // We only have enough states for an m_nCount, so we'll only fill that many.
    if(nCount > m_nCount)
        nCount = m_nCount;
    
    for(unsigned int nIndex = 0; nIndex < nCount; ++nIndex)
        pStates[nIndex] = m_pStates[nIndex];
}

void dftCommon::StateMachine::LoadStates(const dftCommon::Value* pStates, unsigned int nCount)
{
    assert(pStates != 0);
    
    // We only have enough room for m_nCount states, so we'll only get that many.
    if(nCount > m_nCount)
        nCount = m_nCount;
    
    for(unsigned int nIndex = 0; nIndex < m_nCount; ++nIndex)
        m_pStates[nIndex] = pStates[nIndex];
}



enum TEST_STATES { TEST_TITLE = 0 };

dftCommon::StateMachine g_StateMachine;
g_StateMachine.SetState(TEST_TITLE, "StateMachine Test");
I've stepped through it with my debugger, but the constructor code is never called. Did I miss something or is this a bug with MSVC++ 6? It stops on line 19 (the assertion in dftCommon::StateMachine::SetState().) [Edited by - Programmer16 on June 23, 2005 12:58:00 AM]

Share this post


Link to post
Share on other sites
try calling the constructor you created instead of the default one:


dftCommon::StateMachine g_StateMachine(1024);
g_StateMachine.SetState(TEST_TITLE, "StateMachine Test");



I am not sure whether or not a default constructor with no arguments that does nothing gets created for you, or if all that happens is that the memory for your object gets allocated, but either way, your constructor will never get called if you dont provide the required arguments.

Share this post


Link to post
Share on other sites
I guess I should've figured that it would call the default constructor instead of the one with the default parameter. Thanks!

Edit:
Okay, I've changed it to this:
dftCommon::StateMachine g_StateMachine(16);

And my constructor is still not getting called.

I'm not getting any errors, warnings, nothing. And it goes to SetState() correctly.

Edit 2:
Okay, I was trying to run to cursor, but that didn't work so I put a breakpoint in my constructor. It gets called, I stepped through it and all of the data and everything was created correctly. I then did run to cursor in SetState(), but by then m_nCount is 0 somehow.

Edit 3:
Okay I fixed it. I've never used memset() before and I was calling memset(&m_pStates, 0, nStates); (similiar to ZeroMemory()).

[Edited by - Programmer16 on June 22, 2005 9:17:18 PM]

Share this post


Link to post
Share on other sites
You know, it would probably be wise to keep nStateCount on a member variable, to check for bounds and such and for walking the array if needed.

Or you could use a std::vector instead, or even better a std::stack, since it's a state machine.

Share this post


Link to post
Share on other sites
Quote:
Original post by Shannon Barber
That code shouldn't compile - perhaps you are debugging an old executable?
If you declare a non-default ctor, it hides the default ctor unless you explicitly add it.

dftCommon::StateMachine g_StateMachine;

...should fail.


No, this is code I wrote today. I thought that it should fail too, but maybe its just a bug in VC++ 6 or something. But I thought it would call the constructor since I supplied a default value for nStateCount.

@Kwizatz: I do store the number of states: m_nCount. I also do bounds checking (assert(nCount < m_nCount); etc.)

Anyway, I've done away with this code (sent it to the archive), since I've decided that its not needed. Thanks for the help guys.

Share this post


Link to post
Share on other sites
maybe i'm blind, but where is the default value you talk about?
Perhaps you copied an old version?
As written you never supplied the default value.

Share this post


Link to post
Share on other sites
Quote:
Original post by Amnesty
maybe i'm blind, but where is the default value you talk about?
Perhaps you copied an old version?
As written you never supplied the default value.


Oops, I posted the code after I removed it. I did have a default value of 16.

Quote:
STLDude
Why don't you use the debbuger and step into
dftCommon::StateMachine g_StateMachine(16);
to see what gets called.


Quote:
Programmer16
I've stepped through it with my debugger, but the constructor code is never called. Did I miss something or is this a bug with MSVC++ 6? It stops on line 19 (the assertion in dftCommon::StateMachine::SetState().)


Quote:
Programmer16
Okay, I was trying to run to cursor, but that didn't work so I put a breakpoint in my constructor. It gets called, I stepped through it and all of the data and everything was created correctly. I then did run to cursor in SetState(), but by then m_nCount is 0 somehow.


Okay guys, I figured out the problem. I was using memset() (instead of ZeroMemory(), which I usually use) incorrectly.

Thanks for the help!

Share this post


Link to post
Share on other sites
memset and ZeroMemory, and everything else along similar lines, are dangerous things to be using with class instances (only really acceptable with POD-types, and even then, usually needlessly tricky). Just write a proper default ctor for Value instead; it will be called for each instance when the array is allocated. Better yet, use std::vector which among its other benefits is also able to separate memory allocation from instance initialization, and will keep things running smoothly and efficiently for you behind the scenes :)

Share this post


Link to post
Share on other sites
Quote:
Original post by Zahlman
memset and ZeroMemory, and everything else along similar lines, are dangerous things to be using with class instances (only really acceptable with POD-types, and even then, usually needlessly tricky). Just write a proper default ctor for Value instead; it will be called for each instance when the array is allocated. Better yet, use std::vector which among its other benefits is also able to separate memory allocation from instance initialization, and will keep things running smoothly and efficiently for you behind the scenes :)


OMG, I'm so stupid. The memset() call was left from when I was using a long data-type. I didn't really think that this merited a vector, since I don't need to change the size of the array at any time other than the constructor.

Share this post


Link to post
Share on other sites
I don't know how big a Value is, but if it's larger than a single byte, then memset(&m_pStates, 0, nStateCount); isn't right.

Actually, it isn't right anyway, you're taking the address of the pointer you silly person. Where is your pointer located? At the beginning of your class. That would explain why m_nCount ends up being 0, you're basically zeroing your class. And what ever is after it. Memory corruption, mmm, tasty.

Try memset(m_pStates, 0, nStateCount * sizeof *m_pStates);

Share this post


Link to post
Share on other sites
You can test if it is called by creating a simple console application and doing something like this:
#include <iostream.h>

class CTest {
public:
CTest(int arg=16) {
bob=arg;
cout << "Constructor called. arg=" << arg << "\n";
}
~CTest() {
cout << "Destructor called.\n";
}
int bob;
};

int main() {
//Test the different stuff
CTest TestA, TestB(14);
CTest *pTest=new CTest; //Parenthesis? (I forgot if they were necessary)
delete pTest;
//And put something here to prevent the program from automatically closing
system("PAUSE");
}


If the constructor with the default argument is called, then the output ought to look like this:
Constructor called. arg=16
Constructor called. arg=14
Constructor called. arg=16
Destructor called.
If not:
Contructor called. arg=14.
Destructor called.
EDIT: Was this already answered? *Prepares to feel stupid*

Share this post


Link to post
Share on other sites
Quote:
Original post by smart_idiot
I don't know how big a Value is, but if it's larger than a single byte, then memset(&m_pStates, 0, nStateCount); isn't right.

Actually, it isn't right anyway, you're taking the address of the pointer you silly person. Where is your pointer located? At the beginning of your class. That would explain why m_nCount ends up being 0, you're basically zeroing your class. And what ever is after it. Memory corruption, mmm, tasty.

Try memset(m_pStates, 0, nStateCount * sizeof *m_pStates);

Quote:
Original post by Programmer16
Okay I fixed it. I've never used memset() before and I was calling memset(&m_pStates, 0, nStates); (similiar to ZeroMemory()).


Yeah, I said that I was using it wrong (I'm used to using ZeroMemory()). Value has a std::string, int, bool, and a bool (*)() function pointer in it.

Quote:
Original post by deadimp
EDIT: Was this already answered? *Prepares to feel stupid*


Yeah, this was already answered, but I'm the one that should feel stupid (I didn't even think of that.)

Share this post


Link to post
Share on other sites
Quote:
Original post by Programmer16
Yeah, I said that I was using it wrong (I'm used to using ZeroMemory()). Value has a std::string, int, bool, and a bool (*)() function pointer in it.


!!!

Then you should definitely not attempt to use memset, ZeroMemory or anything along those lines on a Value - at all - ever. You're trashing std::string internals like that - even an "empty" std::string might, depending on implementation, expect to contain a pointer to a valid memory allocation.

Actually, the default constructor for a Value would be equivalent to (AFAIK):


Value::Value() : theString(), theInt(0), theBool(false), theFunctionPointer(0) {}


Which means you probably don't really need to do anything at all.

Share this post


Link to post
Share on other sites
Quote:
Original post by deadimp
You can test if it is called by creating a simple console application and doing something like this:
*** Source Snippet Removed ***


#include <iostream.h> is non-standard and support is starting to be phased out on recent compilers, the standard header is <iostream> - no .h

Share this post


Link to post
Share on other sites
Quote:
Original post by Zahlman
Quote:
Original post by Programmer16
Yeah, I said that I was using it wrong (I'm used to using ZeroMemory()). Value has a std::string, int, bool, and a bool (*)() function pointer in it.


!!!

Then you should definitely not attempt to use memset, ZeroMemory or anything along those lines on a Value - at all - ever. You're trashing std::string internals like that - even an "empty" std::string might, depending on implementation, expect to contain a pointer to a valid memory allocation.

Actually, the default constructor for a Value would be equivalent to (AFAIK):


Value::Value() : theString(), theInt(0), theBool(false), theFunctionPointer(0) {}


Which means you probably don't really need to do anything at all.


I didn't think about that (silly me), but you're saying that it will automagically give me a constructor that will set all of my values to zero? Becuase it doesn't (unless I misunderstood what you're saying, which is quite possible since I just woke up.)

Edit:
Also, as I said, the call to memset was left over from when I was using longs. I didn't need to call memset() (or ZeroMemory()) because the default constructor for Value() does set them to their default values.

Share this post


Link to post
Share on other sites
Quote:
Original post by Programmer16
Quote:
Original post by Zahlman
Actually, the default constructor for a Value would be equivalent to (AFAIK):


Value::Value() : theString(), theInt(0), theBool(false), theFunctionPointer(0) {}


Which means you probably don't really need to do anything at all.


I didn't think about that (silly me), but you're saying that it will automagically give me a constructor that will set all of my values to zero? Becuase it doesn't (unless I misunderstood what you're saying, which is quite possible since I just woke up.)


Er, I am quite probably mistaken on that count :) If so, just fill in the ctor illustrated above; it should do the trick.

Share this post


Link to post
Share on other sites

This topic is 4558 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this