LinuxQuestions.org

LinuxQuestions.org (/questions/)
-   Programming (http://www.linuxquestions.org/questions/programming-9/)
-   -   in which case the printf in c++ constructor will cause crash ? (http://www.linuxquestions.org/questions/programming-9/in-which-case-the-printf-in-c-constructor-will-cause-crash-4175422198/)

5883 08-15-2012 10:30 AM

in which case the printf in c++ constructor will cause crash ?
 
if i just put printf in class constructor, it crashes,
any hints ?

NevemTeve 08-15-2012 10:55 AM

Use a debugger, it's quite likely your own fault. (You may quote some source code here, to help us help you.)

sundialsvcs 08-15-2012 12:39 PM

A constructor is an initialization subroutine that is called when an object is being instantiated. The memory block has been allocated and partially initialized; the value has not yet been stored into whatever variable will contain the pointer to the finished object. In general, this is not a good place to "do" anything.

What I customarily do is to define another method, which I customarily call init(), which I call immediately after the contructor.

For instance, I will do: foo* foopy = new foo(); foopy->init();

Notice that the object has been fully instantiated, and stored into the variable ("foopy"), before in the next statement my init() routine is called.

Even if the init routine is "do-nothing" it is still my custom to call it. This is an "ordinary" method against an "ordinary" object by now, and it can therefore do anything it pleases.

In destructors, it is also my custom (painfully learned from an experience that literally cost me $10,000.00 :cry: ) to expressly set every local variable that points to something to NULL, in the very next statement. Also to bracket this with a try..finally block to make damn sure(!) that the pointer does not point to garbage, however briefly. Even if the free() call fails, the pointer still becomes NULL.

johnsfine 08-15-2012 02:04 PM

Quote:

Originally Posted by 5883 (Post 4754707)
if i just put printf in class constructor, it crashes,
any hints ?

A wild guess, you tried to print the object being constructed and accidentally made another object of the same type causing a recursive call to the same constructor leading to a stack overflow crash.

If you would prefer better than a wild guess, provide code or more information.

It is not inherently wrong to call printf in a constructor, so you must have done something else wrong.

dwhitney67 08-15-2012 03:54 PM

Quote:

Originally Posted by sundialsvcs (Post 4754776)
The memory block has been allocated and partially initialized; the value has not yet been stored into whatever variable will contain the pointer to the finished object.

What are talking about? Perhaps you had a "bad day" whilst using the body of the constructor to initialize the class. The class should be initialized before entering the body of the constructor.

Code:

class Foo
{
public:
    Foo(const size_t reqDataSize);
    ~Foo();
private:
    char*  data;
    size_t dataSize;
};

...

Foo::Foo(const size_t reqDataSize)
    : data(new char[reqDataSize]),    // <--- this is the section where a class should be initialized
      dataSize(reqDataSize)
{
    // when we reach this point, the class is fully constructed, providing
    // of course, due diligence is applied when filling in the area above.

    // now, at this point we may want to perform "sanity" check on class members
    // or perhaps even initialize the data with values.
    if (!data)
    {
        throw WeAreOutOfMemory();
    }
    for (size_t i = 0; i < dataSize; ++i)
    {
        data[i] = 'a' + (rand() % 26);
    }
}

Foo::~Foo()
{
    delete [] data;
}

Quote:

Originally Posted by sundialsvcs (Post 4754776)
What I customarily do is to define another method, which I customarily call init(), which I call immediately after the contructor.

In certain cases, this approach is useful, but not for the reason you pointed out earlier.

Quote:

Originally Posted by sundialsvcs (Post 4754776)
In destructors, it is also my custom (painfully learned from an experience that literally cost me $10,000.00 :cry: ) to expressly set every local variable that points to something to NULL, in the very next statement. Also to bracket this with a try..finally block to make damn sure(!) that the pointer does not point to garbage, however briefly. Even if the free() call fails, the pointer still becomes NULL.

I'm not sure why you care whether a pointer is pointing to NULL after it has been freed. As long as you don't use it after it has been freed, your application should be fine. As for the object that contains the dangling pointer, even it should not be used after the destructor has been invoked.

In the example I demonstrated earlier, a smart-pointer (e.g. boost::shared_array) would be preferable to use than a raw pointer. That way I would not have to worry about freeing the allocated memory when the class object is destroyed.

Everyone has unique experiences in life, and I would be entertained to hear how you lost $10K on a project.

5883 08-15-2012 05:50 PM

Thanks for everyone's help, my case is pretty different, this is running in a ARM board,
i suspect missing correct libs, also some memory corruption before i new the object ...

For following might not be from the constructor, but gives you some info,

Program terminated with signal 11, Segmentation fault.
#0 0x40836fbc in malloc_get_state () from /lib/libc.so.6
(gdb) bt
#0 0x40836fbc in malloc_get_state () from /lib/libc.so.6
#1 0x408059cc in vfprintf () from /lib/libc.so.6
Backtrace stopped: previous frame inner to this frame (corrupt stack?)

dwhitney67 08-15-2012 07:42 PM

Quote:

Originally Posted by 5883 (Post 4754997)
Thanks for everyone's help, my case is pretty different, this is running in a ARM board,
i suspect missing correct libs, also some memory corruption before i new the object ...

For following might not be from the constructor, but gives you some info,

Program terminated with signal 11, Segmentation fault.
#0 0x40836fbc in malloc_get_state () from /lib/libc.so.6
(gdb) bt
#0 0x40836fbc in malloc_get_state () from /lib/libc.so.6
#1 0x408059cc in vfprintf () from /lib/libc.so.6
Backtrace stopped: previous frame inner to this frame (corrupt stack?)

Well thank God it's not from your code.

johnsfine 08-15-2012 08:36 PM

Quote:

Originally Posted by 5883 (Post 4754997)
i suspect missing correct libs

Strange guess. I really doubt that is correct.

Quote:

some memory corruption before i new the object
That is possible, but there are lots of possibilities since you provide no useful information.

Quote:

For following might not be from the constructor, but gives you some info,
That improbable stack fragment gives almost no information. Looking at that stack fragment, I would guess that some function overwrote its own return address on the stack so it did a wild jump when attempting to return, so it landed in malloc_get_state by accident. But I have no confidence in that guess.

bdd 08-16-2012 07:31 AM

Some possbilities come to mind:
- Is the object statically defined; i.e., not in a function? (though you did say you 'new' it)
- The printf format string does not match the items you have supplied (did you see a compiler warning?)
e.g.,
printf( "%s %s\n", "string1" );
- Did you specify a huge or negative field length?
- Is it possible that your compiler does not support the printf option(s) you are specifying? This is sometimes the case with embedded systems.

It would help to see the line of code (properly obfuscated, I suppose).

sundialsvcs 08-16-2012 10:31 AM

Quote:

What are talking about? Perhaps you had a "bad day" whilst using the body of the constructor to initialize the class. The class should be initialized before entering the body of the constructor.

Code:

class Foo
{
public:
    Foo(const size_t reqDataSize);
    ~Foo();
private:
    char*  data;
    size_t dataSize;
};

...

Foo::Foo(const size_t reqDataSize)
    : data(new char[reqDataSize]),    // <--- this is the section where a class should be initialized
      dataSize(reqDataSize)
{
    // when we reach this point, the class is fully constructed, providing
    // of course, due diligence is applied when filling in the area above.

    // now, at this point we may want to perform "sanity" check on class members
    // or perhaps even initialize the data with values.
    if (!data)
    {
        throw WeAreOutOfMemory();
    }
    for (size_t i = 0; i < dataSize; ++i)
    {
        data[i] = 'a' + (rand() % 26);
    }
}

Foo::~Foo()
{
    delete [] data;
}

In certain cases, this approach is useful, but not for the reason you pointed out earlier.
At the time the constructor is executing, the object is indeed fully-formed, although perhaps not fully initialized, but the variable that will ultimately point to the object is still uninitialized with the correct value. Furthermore, there might be a chain of constructors of which this is only one. (You must be mindful of the situation where code worked just fine when originally written, but subsequent extensions or changes to the class structure cause it to later misbehave, etc.) Therefore, the overall situation is, shall we say, "a bit half-cooked."

Hence my practice of defining a separate "initialization" routine. This routine can safely assume not only that the object is fully prepared (no matter how many constructors may have fired), but that its surrounding context is truly ready-to-go. (I sometimes find it useful to do the same thing when an object is going-away, especially when the going-away process might involve, say, sending some kind of a notification message across a socket or an IPC connection or some-such.) In short, "this works for me." "This works really well for me." When you've just created someone, give 'em a moment to comb their hair. And, when you're about to shoot someone, give 'em that last cigarette. :)

Quote:

I'm not sure why you care whether a pointer is pointing to NULL after it has been freed. As long as you don't use it after it has been freed, your application should be fine. As for the object that contains the dangling pointer, even it should not be used after the destructor has been invoked.

In the example I demonstrated earlier, a smart-pointer (e.g. boost::shared_array) would be preferable to use than a raw pointer. That way I would not have to worry about freeing the allocated memory when the class object is destroyed.

Everyone has unique experiences in life, and I would be entertained to hear how you lost $10K on a project.
The $10,000 problem was ultimately a "double free," in code that I bought but did not write, in a language other than C++. The destructor freed the memory then called the parent. The parent destructor in the destructor chain attempted to reference the non-NULL pointer that now pointed to freed data. In the case at bar (Windows 3.1) not only the application but the entire operating environment disappeared: one moment you're running a mission-critical app; the next instant you're at a MS-DOS prompt, and everything you need to resolve the problem is gone. (Even exception-handling did not work.) I could not resolve the issue and had to give a fat refund. (The story has a somewhat happy ending because the customer was so impressed that we were willing to do what our contract promised, that he didn't sell us down the river.)


All times are GMT -5. The time now is 08:36 PM.