0

So after working on my last question, I boiled it down to this:

I need to add an unknown number user-defined classes (object_c) to a boost::intrusive::list. The classes have const members in them. All I need to do to push them to the list is to construct them and then have them persist, they automatically add themselves.

The code in question is basically

for (unsigned i = 0; i < json_objects.count(); ++i) {

    ctor_data = read(json_objects[i]);

    // construct object here

}

What I've tried:

  1. mallocing an array of objects, then filling them in: Doesn't work, because I have const members.

    static object_c *json_input = (object_c*) malloc(json_objects.size() * sizeof(object_c));
    
    ...
    
    json_input[i](ctor_data); //error: no match for call to (object_c) (ctor_data&)
    
  2. Making a pointer: This doesn't work, functions don't work properly with it, and it doesn't get destructed

    new object_c(ctor_data);
    
  3. Pushing the object back to an std::vector: This doesn't work, boost rants for dozens of lines when I try (output here)

    vector_of_objects.push_back(object_c(ctor_data));
    
  4. Just declaring the darn thing: Obviously doesn't work, goes out of scope immediately (dur)

    object_c(ctor_data);
    

I'm sure there is an easy way to do this. Anyone have any ideas? I've been at this problem for most of the weekend.

Community
  • 1
  • 1
pmelanson
  • 330
  • 4
  • 16
  • 1
    When you mean `class` do you mean `object` – Karthik T Jan 28 '13 at 01:18
  • @KarthikT `object_c` is a user-defined `class`. Kind of a not-good choice of name, but I can't think of many better names for an object in space. – pmelanson Jan 28 '13 at 01:22
  • I meant in your first paragraph. – Karthik T Jan 28 '13 at 01:24
  • yes, I'll edit that to clear it up – pmelanson Jan 28 '13 at 01:26
  • Btw u should think of a better name (or is this just for the benefit of this question?) – Karthik T Jan 28 '13 at 01:27
  • 1
    in a way it's good that you have const member(s), because that informs you of all the undesired copy attempts. so i won't suggest removing the constness of those members. rather, keep it and make things work. – Cheers and hth. - Alf Jan 28 '13 at 01:29
  • 1
    I'm not entirely sure what you are trying to do, but if you go with #1 you need to use placement new when constructing from a malloced pointer: `new (&json_input[i]) object_c(ctor_data)`. – rasmus Jan 28 '13 at 01:30
  • @KarthikT I probably should, I've just never needed to so far because this is a monopoly project and I've always been able to tell the difference. I'm thinking I'll change it to `entity_c` – pmelanson Jan 28 '13 at 01:35
  • 1
    I can see this being very problematic if the const value is *dynamic* at construction, something like this (admittedly broken) idea: `Type value[10](++i);` where each constructor was passed a different value. but for *all* of the objects to be passed the *same* value to set as a member-const, why not just use a non-member const and skip the construction issues altogether? – WhozCraig Jan 28 '13 at 01:39
  • @rasmus I'm trying to make `object_c json_input[json_objects.count()]`, and then replace all the `malloc`'d memory in the array with constructed objects. I ran that code through and it gives the same output as (2) – pmelanson Jan 28 '13 at 01:43
  • So what output does (2) give? I'm not sure what "functions don't work properly with it" means. Also, the destruction issue must be handled by calling the destructors explicitly on the pointers when using placement new. This could be handled in a helper class. – rasmus Jan 28 '13 at 01:52
  • @rasmus For example, when I first spawn them into space, they are at the correct positions, but after doing stuff like moving them, their positions change randomly, although if they are both 0, they will both be, for example, -392368 by the time the program finishes. – pmelanson Jan 28 '13 at 01:58
  • Sorry, but it is impossible to help you more with the information at hand. Getting garbled numbers when the program finishes indicates that the memory was freed or otherwise corrupted. – rasmus Jan 28 '13 at 02:09
  • more information it is then. The failure occurs when it exits the read/construct loop. Here is my [call stack](http://pastebin.com/gut5TVDT) at the time of the failure. Note there is a bunch of `std::` destruction functions in there, followed by `boost::` functions. And here is [my program log](http://pastebin.com/9szBL4ME) until the failure. I've seen that pattern of it destructing before it should when the data goes out of scope. I'm guessing the vector is destructing the stuff, but I don't know why. – pmelanson Jan 28 '13 at 02:23
  • Please post your code exactly as you run it now. If you really are using `object_c json_input[json_objects.count()]` that is obviously wrong since it is allocated on the stack. You need to use malloc as in your #1 case. – rasmus Jan 28 '13 at 02:39
  • [here's the function](http://pastebin.com/kWEq01Zf), relevant stuff begins at line 27. I'll push what I have right now to [github](https://github.com/patrickpowns/corbit/) – pmelanson Jan 28 '13 at 02:44
  • @rasmus I've got an exam in the morning so I guess I'll cut it off here, sleep on it, then try all these suggestions and permutations thereof again (thanks a lot for the suggestions btw). I'll probably find out that it's just an off-by-one error or something equally ridiculously basic, judging by past experiences. Of course, I'll post an answer here if I find the error. – pmelanson Jan 28 '13 at 03:39
  • 1
    It looks like it may be a static initialization order issue at work judging from the assert. Maybe you can try to store a pointer to the object list and create it first thing in main. – rasmus Jan 28 '13 at 03:46

3 Answers3

2

#3 should be the method you need to use. You need to elabourate on what your errors are.

If it is just operator= as you show in your previous question, and you dont want to define one, you can try emplace_back as long as you are in C++11. Of Course I am talking std::vector, I need to check what is the equivalent if any in boost::intrusive. Edit: I might be wrong, but it doesnt seem to support move semantics yet..

Alternatively use #2 with smart pointers.

If you are going with #1, you would need to use placement new as @rasmus indicates.

Karthik T
  • 31,456
  • 5
  • 68
  • 87
  • I tried defining an `operator=` according to [this question](http://stackoverflow.com/questions/3279543/what-is-the-copy-and-swap-idiom), which required me to say `std::swap(first.a_const_member, second.a_const_member);`, which gave me an error, though not for my non-const members. Also, I think that `emplace_back` might be what I'm looking for, I'll try that out momentarily. Also, boost error [enclosed](http://pastebin.com/qGkC0Zcp) – pmelanson Jan 28 '13 at 01:33
  • 1
    @PatrickPowns Yes, I expect const members would make it non copyable. – Karthik T Jan 28 '13 at 01:34
  • yeah, I was just trying to see if it could somehow work (obviously it didn't, just exhausting all possibilities) – pmelanson Jan 28 '13 at 01:38
  • +1, I'm thinking #1 with placement-new is a pretty good candidate by the sound of the surrounding use-case. – WhozCraig Jan 28 '13 at 01:42
1

At the end of the documentation's usage section it tells you that

“The lifetime of a stored object is not bound to or managed by the container”

So you need to somehow manage the objects’ lifetime.

One way is to have them in a std::vector, as in the documentation’s final example.

Cheers and hth. - Alf
  • 142,714
  • 15
  • 209
  • 331
  • that's what (3) should be like, but it gives a [boost error](http://pastebin.com/qGkC0Zcp). Which is weird, because it looks much like their example. My implementation is in [this pastebin](http://pastebin.com/rpfZi3zX) – pmelanson Jan 28 '13 at 01:49
  • the assertion seems to say that you have uninitialized pointer values with garbage non-zero values. googling i found a routine called `init`. maybe you need to call it. – Cheers and hth. - Alf Jan 28 '13 at 02:06
  • what do you mean by `init`, where/what do I call it from? – pmelanson Jan 28 '13 at 02:31
  • never mind, i just found it by googling the assertion. but it should be called automatically. so, i think the thing to do is to *reproduce the problem* in a minimal, complete program. – Cheers and hth. - Alf Jan 28 '13 at 07:26
0

Sorry for the late reply, exam studying and all that.

It was simpler than I was making it out to be, basically. Also, for this answer, I'm referring to my class as entity_c, so that an object of entity_c actually makes sense.

What I was doing in my OP was when I push_back'd an entity_c, it was automatically adding itself to a global intrusive::list, and somehow that made it not work. After I stopped being lazy, I wrote up a minimal compilable progam and played around with that. I found out that making an std::vector to store the constructed entity_cs in worked (even though it deconstructs them when they're added? I dunno what that's about). Then all I had to do was populate a local intrusive::list with those objects, then clone the local list into the global list.

Thanks for all the help, I'll tweak that program to try and fit in different stuff, like placement new suggested by @rasmus (thanks for that, hadn't seen that before). Also thanks to @karathik for showing my emplace_new, I think I might have to go and find out about all these new C++11 features that have been added in, there are so many cool ones. I even learnt how to make my own copy constructor.
Truly and edifying educational experience.

pmelanson
  • 330
  • 4
  • 16