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:
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&)
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);
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));
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.
#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.
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.
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.
Related
First time I'm posting to stack so if I'm not following the correct procedure, instruct me to do better and I will.
Ok, I have quite a big project with lots of classes and I cannot share code at this point, but if necessary I will write a dummy file to further explain. Hopefully I will be clear enough without that.
I have this class method that receives as params a vector: std::vector< myClass > &objects_1.
Some of these will be bound (logically) to other objects in the class. The important thing to keep in mind is that I have to modify some of the received objects_1 without using the vector indexing (as it may change along the way)
Also unfortunately it is relevant for the function to have this exact signature.
The way I do it now is by having several pointers initialized with nullptr that, sooner or later point to elements of the objects_1 vector.
My questions are: is this a bad practice? Do I have to delete the pointer or does the destructor takes care of this? Is there a better way to do this? I tried std::shared_ptr but as someone pointed out these are intended more for allocating memory dynamically.
I am reading C++ Primer and find these kinda confusing:
The reset member is often used together with unique to control changes
to the object shared among several shared_ptrs. Before changing the
underlying object, we check whether we’re the only user. If not, we
make a new copy before making the change:
if (!p.unique())
p.reset(new string(*p)); // we aren't alone; allocate a new copy
*p += newVal; // now that we know we're the only pointer, okay to change this object
What does the emphasized text mean in the quoted text above? So confused.
Update:
After reading the text again, I find out that I may miss something.
So according the code above, let's assume there are 2 shared_ptr (one is p mentioned here) pointing to the original dynamic memory object let's say A. Then if I want to modify object A, I allocate a new dynamic memory with the copy value of A(new string(*p)), assign it to p, let's say B. So eventually A is not modified, but only create a copy of modified version of A?
Why not directly do *p += newVal;? And why is it related to Copy-on-write mentioned in answers? I mean, there's no extra copy operation needed. All shared_ptr originally points to dynamic memory object A. Only 1 object.
Screenshot that may supply a little bit more context:
I think authors of the book described here how Copy-on-write paradigm can be implemented using shared_ptr. As mentioned in comments before "this isn't a requirement of shared_ptr, its simply a design decision".
For you are only allowed to modify the shared_ptr and not the objects they refer to. This is to prevent data races.
From util.smartptr.shared/4:
For purposes of determining the presence of a data race, member
functions shall access and modify only the shared_ptr and weak_ptr
objects themselves and not objects they refer to.
Changes in
use_count() do not reflect modifications that can introduce data
races.
For the reset() member function:
void reset() noexcept;
Effects: Equivalent to shared_ptr().swap(*this).
Update: Substantially revised, based on new knowledge.
Short answer (to the title of your question): you don't. What C++ primer are you reading? No way is the example you quote there primer material.
The whole idea behind smart pointers is that they 'just work', once you understand them properly, and the author of the passage has pulled a stunt here which would rarely, if ever, be used in practice.
He appears to be trying to describe some sort of oh-so-slightly-weird copy-on-write mechanism implemented in software, but he has clearly bamboozled the OP and no doubt most of the rest of his readership in doing so. It's all a bit silly and it's just not worth trying to understand why they present it as they do (or, indeed, just what it is supposed to do in the first place). Like I say, it has no place in a primer (or probably anywhere else).
Anyway, std::shared_ptr::unique() is flawed (it is not threadsafe) and will be going away soon.
It should probably never have existed in the first place, don't use it.
One other issue arose during various discussions in the thread, and that is whether it is safe to mutate an object managed by a shared_ptr. Well wherever did you get the notion that it isn't? Of course it is. If you couldn't, many programs simply could not be written at all. Just don't mutate the same object from two different threads at the same time (that's what the standard calls a data race) - that's the only issue. If you do want to do that, use a mutex.
I am doing some assignment and i am not good at understanding pointers. Please help me understand what argument i need to pass to this function.
void City::setList(List<City*> *l){list = l;}
Without seeing the definition for List (and because Google is case-insensitive), I can't give an exact answer, but you'll want to construct it something like this:
List<City*> myList;
Then (assuming List works like Java's List):
City c; //Or with constructor, or whatever
myList.add(&c);
To call your method:
// `d` is some other City
d.setList(&myList);
There's one major caveat, though: Unless you created c with new (which, given the syntax example I used here, you probably didn't), any pointers to it are going to be dangling as soon as c goes out of scope. You'll want to make sure you aren't doing that. And if you create it with new, you have to be sure to delete it later.
I had two matching vectors of unique_ptr. I decided to unify them by making one vector of structs containing two unique_ptr (the struct will also contain other items, eventually, hence this refactoring).
What is the best approach for me to add new items in this vector?
My current code is
std::vector<DestinationObjects> destinations;
for (unsigned short &id: ids) {
DestinationObjects d;
d.transmitter = unique_ptr<Transmitter> (new Transmitter(id));
d.controller = unique_ptr<Controller> (new Controller(id));
destinations.push_back(d);
}
Of course this copies d, causing issues with unique_ptr. What is the best approach to fixing this?
Options I can conceive of, some of which I am not sure will work:
Just switch to shared_ptr. (A simple find-replace, but feels like a cop-out).
Write a move constructor for the struct that moves the unique_ptr. (Another thing to maintain that could go wrong, as I expand the struct).
Push back an empty struct instance with null pointers for the unique_ptr and edit these in place once in the vector. (Fiddly syntax. Also I'm not sure this would even work).
Any ideas what would be another approach? Or why I should prefer one of the ones I have listed?
Simpley do a vec.emplace_back( std::move(d) ).
If (as mentioned in your comment) your compiler does not implement implicit move construtors, write your own move constructor. My advice in the future is whenever you have a problem with any C++11 feature and are asking a question, mention that you are using this compiler, as there is a pretty good chance that it's "C++11 support" will be an important issue.
If your compiler does not support any move constructor at all, stop using unique_ptr -- they are rather useless without move constructors. ;)
I need make a class, let's say FineStack, who should declare a structure able to manage different kind of Fines ( LightFine, SeriousFine ). The superclass for both is Fine.
The question is, do I really need templates? I thought it was not necessary, so this is what I thought:
-> declare Fine *fines; ( kind-of array of fines? ) And ... creating an array of Fine's objects (the superclass), it should be able to manage both LightFine and SeriousFine objects.
-> The problem is. How should I declare it? Fine should be an abstract class, so no instances could be created (instances should be either LightFine's or SeriousFine's ).
I got stuck with this, since I don't find the way to get it. I've read in multiple questions here in Stackoverflow, that you guys usually suggest to use std::vector , which makes you easier to manage this kind of stuff.
Should I go in that way and forget about the original idea?
I need a structure which should be able to handle any object from both subclasses, in any order (let's say .. 3 LightFine and 2 SeriousFine ... or alternatively each other from the start to the end of the structure ... whatever.
I would like to point you in the right direction and not just give you the whole shebang. If this doesn't help, please ask about what's troubling you:
Although Fine cannot be instantiated, you can point to it, so:
Fine* f1 = new LightFine();
Fine* f2 = new SeriousFine();
are both legal, because LightFine is-a Fine and SeriousFine is-a Fine.
Edit: I see this is not clear yet. If you read the above you can see that I can hold a pointer Fine*, yet have it "secretly" point to either LightFine or SeriousFine. That means, If I were to keep a bunch of Fine* pointers, some of them could be LightFine and some SeriousFine. i.e, I can do this:
Fine** fines = new Fine*[5];
f[0] = new LightFine();
f[1] = new SeriousFine();
...
for (int i=0; i<5; i++) {
std::cout << fines[i]->toString() << std::endl;
}
and the output would be:
a light fine
a serious fine
...
if you do want to use a vector, it too should be of type vector<Fine*> and not vector<Fine>.
You can't have an array of Fines or a vector of fines because the Fine class is abstract (and it should really be).
The solution is to use either an array of pointers (like Fine **fines and fines = new Fine*[whatever-size-you-need]) or a vector of pointers (like std::vector<Fine*> fines). After that, you can instantiate any subclass of Fine with new and it will be implicitly upcasted to Fine* when you put it into the array/vector.
And you certainly don't need templates here, unless you have another (unrelated) reason to use them.
In C++, polymorphism (the ability to have the same code work with objects of multiple different subclasses of a given parent class) is accomplished with pointers and references to base classes, not base class types themselves. If you come from a language like Java this might be confusing, because there all object references implicitly behave like pointers do in C++.
Ideally you should use vector<std::tr1::shared_ptr<Fine> >. The Boost documentation does a good job explaining why shared_ptr simplifies memory management; TR1's shared_ptr is essentially the same as Boost's except that it probably already comes with your compiler.
If you're content to do your own memory management, use vector<Fine*>. Don't use vector<Fine> -- that will cause object slicing.
What is object slicing? LightFine is (possibly) bigger than Fine, so it won't fit in the same amount of memory. If you declared Fine a; LightFine b; a = b; this will compile, but the entire LightFine object won't fit in a, so just the Fine subobject of b will be copied. Essentially the same thing happens when inserting a LightFine object into a vector<Fine>.
You won't be able to treat a as a LightFine object after that assignment, since its static type is just Fine, and all the LightFine "parts" have been discarded anyway. Also, treating a as a Fine object can produce unexpected behaviour -- for example Fine might have an internal data field that is repurposed by LightFine and thus contains an out-of-bounds value when interpreted by Fine's methods.
Revised answer after my first had errors:
Will both LightFine and SeriousFine implement only the interface from Fine, or will they have additional methods that the FineStack will need to know about?
If the FineStack will only interact with the Fine objects using methods defined in Fine's interface, then I don't see a problem with your array approach, as long as you use Fine** fines (i.e. an array of pointers to Fines). Although, I'd tend to use a std::vector<Fine*> instead.
(I did have a comment here about dynamic_cast, but I've removed it after a couple of commentors suggested it was dangerous advice).
sounds like you should go with std::vector<Fine>