2

Somehow I need to make use of a class object inside of a pre-allocated memory. However,g++ doesn't like my code below. It's saying

invalid use of ‘CTest::CTest’ in line 26

How to change this to make it work?

#include <stdio.h>
#include <stdlib.h>
#include <string>

class CTest
{
public:
        CTest(const char* str)
        {
                printf("constructor\n");
                m_str = str;
        }
        virtual ~CTest()
        {
                printf("destructor\n");
        }

        void output()
        {
                printf("output:%s\n", m_str.c_str());
        }

protected:
        std::string     m_str;
};

struct TTT
{
        char    test_ptr[sizeof(CTest)];
};

int main(int argc, char* argv[])
{
        struct TTT* ttt = (struct TTT*)malloc(sizeof(struct TTT));
        CTest* test = (CTest*)(ttt->test_ptr);
        test->CTest("123456");
        test->output();
        test->~CTest();
        return 0;
}
Viet
  • 17,944
  • 33
  • 103
  • 135
stoneyan
  • 871
  • 6
  • 8
  • 5
    See [placement `new`](http://stackoverflow.com/questions/222557/what-uses-are-there-for-placement-new). – DCoder Mar 11 '14 at 18:11

2 Answers2

2

You cannot call the constructor directly. Instead, you have to use "placement new" for your object (What uses are there for "placement new"?). Which basically uses the memory you provide an calls the constructor. You can, however, call the destructor directly--simple call ~CTest() and don't call delete.

Community
  • 1
  • 1
Yasser Asmi
  • 1,150
  • 2
  • 12
  • 27
  • "You cannot call the constructor directly" is wrong. `T()` is an example of calling a constructor directly. Where `T` is a class type. – Cheers and hth. - Alf Mar 11 '14 at 19:25
  • Do you mean T* t = new T()? That is still going via new. You aren't invoking the constructor directly. Calling it via temporary is also creating a new object. You aren't calling a constructor on a particular object in that case either. – Yasser Asmi Mar 11 '14 at 20:48
  • no, i did not mean something other than what i wrote. that includes that no, i did not describe how to create an object in existing storage. i do describe that in my answer to this question. – Cheers and hth. - Alf Mar 11 '14 at 21:21
  • Well, then I don't know why you thought my statement was wrong. There is no way to invoke a constructor directly on an object. If there were, you could invoke it multiple times. The point of a constructor is that you are "constructing" an object--it is not invoking a function separately. It is a part of the creation of the object. – Yasser Asmi Mar 11 '14 at 21:49
  • Your statement does not mention "on an object". That context may be in your mind, but e.g. the title of this question does not force that context. It is a matter of unclear statement, hence I did not downvote. ;-) – Cheers and hth. - Alf Mar 11 '14 at 21:53
  • Sure but that is what the question is about :) – Yasser Asmi Mar 11 '14 at 21:57
1

Regarding the title of the question,

“Can I call the constructor and destructor of a class explicity?”

yes of course, e.g. you're calling the constructor very explicitly every time you create a temporary of the class (explicit destructor calls are more rare).

The standard confused this issue for a long time with its offhand comment “looks like an explicit constructor call”, but quite simply, explicit is explicit, and implicit is implicit, and call is call, and the standard does not redefine these terms. Regarding the term “call” as applied to constructors, the standard refers to source code level constructor “call”s e.g. in the definition of what a default constructor is. Anyway that’s a matter of terminology.

But the real question is different,

“I need to make use of a class object inside of a pre-allocated memory”

For this you can use an allocation function that simply returns the address that you pass it. And the standard library offers such an allocation function via the header <new>. To choose that “dummy” allocation function you can simply pass a pointer to your buffer as argument to it, so that it's selected by ordinary overload resolution.

To pass the pointer argument you can use placement new syntax, as follows:

#include <new>

// ...
 CTest* p_test = ::new (&ttt) CTest( "12345" );

where ttt is the buffer.

Note the global namespace qualification, which in general is needed in order to not pick up an allocation function defined by the class in question.

For this to work nicely –no crash, no fixup delay– the address you use must be of suitable alignment for the class. E.g., it may need to be a multiple of 4, or of 8, depending on the class. If the buffer comes from default new, then no problem, just use the start of the buffer, but I'm not so sure of malloc as it appears you’re using.

Do consult the documentation on that.

C++11 has some support for alignment, but your compiler may not necessarily offer that (yet). For platform-specific code you may not need to address this issue. However, if you want portable code you should make sure of correct alignment.

In practice one way to do it is to make your buffer 16 bytes larger than would strictly be necessary without the alignment requirement, and using a pointer to a place suitably offset from the start of the buffer.

Cheers and hth. - Alf
  • 142,714
  • 15
  • 209
  • 331