-2

I'm facing a problem using VC++ and Debug CRT with a DLL in development.

I have a struct like that, holding some references.

struct DATA
{
    TA*& a;
    TB*& b;
    TC*& c;
    TD*& d;

    char** chars;
    int num_chars;

private:
    // because:
    // DATA a;
    // DATA b;
    // a = b; // is impossible
    DATA& operator=(const DATA&); // append " = delete;" for C++11

    // Default ctor (private because struct should be manually constructed using malloc)
    DATA(TA*& a, TB*& b, TC*& c, TD*& d)
        : a(a),
          b(b),
          c(c),
          d(d),
          chars(NULL),
          num_chars(0)
    {}
};

and construct it like that:

DATA*& Get()
{
    static struct DATA *data = (struct DATA*)malloc(sizeof(struct DATA));
    return data;
}

now it should hold uninitialized ref-to-ptrs, which I want to init by:

void func(TA* a, TB* b, TC* c, TD* d)
{
    Get()->a = a;
    Get()->b = b;
    Get()->c = c;
    Get()->d = d;
    ...
}

which works for everything, but ref-to-ptrs..

I'm getting a INVALID_POINTER_WRITE_FILL_PATTERN_cdcdcdcd on the first Get()->a = a; when I do !analyze -v -f using WinDbg (in a remote Kernel Debugging "kd" instance)

Thanks for your help! :)

Edit: Solution

Solution is to use the points from the correct answer.

Making the c'tor public is necessary:

struct DATA
{
    TA*& a;
    TB*& b;
    TC*& c;
    TD*& d;

    char** chars;
    int num_chars;

    // Default ctor
    DATA(TA*& a, TB*& b, TC*& c, TD*& d)
        : a(a),
          b(b),
          c(c),
          d(d),
          chars(NULL),
          num_chars(0)
    {}

private:
    // because:
    // DATA a;
    // DATA b;
    // a = b; // is impossible
    DATA& operator=(const DATA&); // append " = delete;" for C++11
};

then using placement newto construct the struct:

DATA*& Get(...)
{
    // ... some stuff, overloading, other init-method etc. to init and construct like:
    static struct DATA *data = 
        new(malloc(sizeof(struct DATA))) DATA(...); // At least assign ALL references in the c'tor
    return data;
}

then use it and maybe assign everything that's no reference:

void func(TA* a, TB* b, TC* c, TD* d)
{
    Get(a, b, c, d);

    Get()->chars = ...
    ...
}

free'ing the whole thing needs to be done explicitly by calling the d'tor and free , because we use placement new:

data->~DATA();
free(data);
Dominik P
  • 117
  • 10
  • In C, you don't have reference; in C++, you should't use malloc. choose your language. – Jarod42 Nov 04 '14 at 23:26
  • just down-voting, for what? it's a question I was facing, thereis an excerpt to get an idea how it's working and I pointed out a solution... – Dominik P Nov 05 '14 at 02:58

2 Answers2

2

You cannot declare references without initializing them. Your struct has no default constructor, since you explicitly declare a non-default constructor. Just allocating malloc is not sufficient to create a valid DATA object, as it is a non-POD type.

Just go ahead and try declaring a real default constructor (i.e., DATA() {}), and you'll see that this won't work because of the reference members. If you want to use malloc to allocate non-POD objects, you'll have to use a placement new.

misberner
  • 3,488
  • 20
  • 17
1

Note that malloc() returns uninitialized memory. C++ objects need to be constructed. The way to get an object into uninitialized memory is to use placement new (this code also adds clean-up):

#include <new>
DATA*& Get()
{
    static DATA *data = new(malloc(sizeof(struct DATA))) DATA(...);
    static std::unique_ptr<DATA, void(*)(DATA*)> clean(data,
                                                [](DATA* d){
                                                    d->~DATA();
                                                    free(data);
                                                });

    return data;
}

There is no way in C++ to reseat references, i.e., they need to be set during construction. Personally, I wouldn't use malloc() but rather a suitable allocation anyway:

    static DATA* data(new DATA(...));

... or, as Jarod42 pointed out, actually

    static DATA data(...);
    return &data;
Dietmar Kühl
  • 150,225
  • 13
  • 225
  • 380
  • Just curious, how would you release that memory (the one with placement new)? – David G Nov 04 '14 at 23:28
  • or no allocation at all: `static DATA data(..); static DATA* dataptr = &data;`. – Jarod42 Nov 04 '14 at 23:30
  • @Jarod42: yes, there are many ways. If the use of `malloc()` is required, though, it is interesting to clean up, too... – Dietmar Kühl Nov 04 '14 at 23:34
  • this may be useful to clean up when using `placement new` : http://stackoverflow.com/questions/8918791/how-to-properly-free-the-memory-allocated-by-placement-new – Dominik P Nov 04 '14 at 23:41
  • @DominikP: I prefer my use of `std::unique_ptr<...>()` but, yes, getting rid of these guys isn't entirely straight forward. – Dietmar Kühl Nov 04 '14 at 23:43
  • what happens if `malloc` returns `NULL` in this code? – M.M Nov 05 '14 at 02:04
  • @MattMcNabb: You'll get undefined behavior. Admittedly, I just addressed how to construct an object in the memory. Checking it is there can be done but it gets a bit more involved. – Dietmar Kühl Nov 05 '14 at 02:12
  • My number is 42, not 43. And it misses `static` for `unique_ptr`. – Jarod42 Nov 05 '14 at 08:15