I'm making a class which has a function that concatenates two vectors of unique_ptrs. When I use the push_back function, the size of the parameter vector changes, and I don't know why.
class A: public vector<unique_ptr<int>>{
public:
A& concatenate(A& c);
};
A& A::concatenate(A& c) {
for(int i = 0; i < c.size(); i++) { //this loop never stops
push_back(make_unique<int>()); //this line changes the size of c?
(*this)[(*this).size() - 1] = move(c[i]);
}
return *this;
}
The for loop doesn't stop running because every time the push_back method is used, the size of c is also incremented by 1.
I also thought to use resize() before the for loop, and then move all the pointers, but I want to know why the push_back method changes another vector.
That might happen when this A and the c A objects are same, i.e. you are trying to call concatenate on an object and passing the same object as param to concatenate.
So actually push_back is not changing size of another vector. Its the same vector you are working on.
On a sidenote, there are few issues with your code and post
As #PaulMcKenzie said, you should post an MCVE
In general, its not a good idea to derive from STL containers
Unless you are trying to learn how to implement, you should first try to find and use methods provided by STL containers. e.g. insert as suggested by
#Some programmer dude.
Related
So, I have been working on my assignment for quite a while but stumbled upon a problem that I couldn't solve by myself.
My task was to create a class CompositeShape which would be capable of holding shared_ptr pointers of a base class Shape in a unique_ptr array so that we would then have an array of derived from Shape classes. The CompositeShape by itself is derived from Shape as well.
So, even though the code below works fine and even provides a strong exception guarantee, my teacher says that this particular function can be optimized.
void kosnitskiy::CompositeShape::add(const std::shared_ptr<Shape> &src)
{
if (src == nullptr)
{
throw std::invalid_argument("Attempt to add an empty pointer exception");
}
std::unique_ptr<std::shared_ptr<Shape>[]> shapes(new std::shared_ptr<Shape>[count_ + 1]);
for (int i = 0; i < count_; i++)
{
shapes[i] = std::move(shapes_[i]);
}
shapes[count_] = src;
shapes_ = std::move(shapes);
count_ += 1;
}
My first reaction was to change the array expanding algorithm to something similar to a vector one so that we wouldn't be forced to create a new array every time a new element is being added, but the teacher said, that despite the fact it's a quite good idea, he talks about the different type of improvement. The one, which wouldn't change the class design. So I assume there is a flaw somewhere in a function itself. I have already changed the assignment construction, used in a for loop, from shapes[i] = shapes_[i] to a one using the std::move instead, since I figured that move assignment operator would be way more efficient than a copy assignment one, but I'm pretty much out of ideas now.
I'm not allowed to make any class design changes. I didn't use vector because it was specified by the teacher that we can't use any standard containers. I didn't use weak_ptr for the same reason as well: we were told only to use unique_ptr and shared_ptr pointers. Non-smart pointers are blocked as well
Thank you very much for your help in advance
My guess is, that teacher's remark might about passing src by value and moving it into the array.
Another option would be to use std::move with std::begin/end instead of a raw for loop.
But both of those seem to be micro-optimizations with the array growing by 1 and being reallocated with each addition and are out of context.
I have such private field:
private:
std::vector<OneItemIndex> oneItemIndexes;
My class declared this way, there are no default constructor:
public OneItemIndex(int instrumentId)
I want my field to contain 10 elements like this:
oneItemIndexes
0 OneItemIndex(0)
1 OneItemIndex(1)
...
10 OneItemIndex(10)
How can I do this? What should I write in constructor? Is it possible?
Or I have to use OneItemIndex* instead of OneItemIndex and call new OneItemIndex(instrumentId myself this way?
IndexesStorage::IndexesStorage(void)
{
for (int i = 0; i < 10; i++) {
oneItemIndexes.push_back(new OneItemIndex(i));
}
}
Note: actually I dont' have hardcoded 10 elements, i'm using dynamic Instrument::InstrumentsCount()
In C++11 and later, you can initialise container elements by passing constructor arguments to an emplace function:
oneItemIndexes.emplace_back(i);
Historically, you could copy-initialise them (as long as they're copyable; but that was a requirement for vector before C++11):
oneItemIndexes.push_back(OneItemIndex(i));
I don't understand the leap to dynamic allocation in the middle of your question. Why do you think you suddenly have to use dynamic allocation and store pointers?
Use your loop, but with normal, automatic-storage-duration objects. oneItemIndexes.push_back(OneItemIndex(i)) or even oneItemIndexes.emplace(i).
You could use std::generate. Sorry for brevity of my answer but I am on my phone.
If you really don't want to make your object default-constructible and copyable, the easiest way to solve this would be to use a vector of shared_ptrs to OneItemIndex. This way you get the copy/initialize semantics vector requires from shared_ptr, but you don't need to have them on OneItemIndex itself (a raw pointer would work too, but then you need to take care of deleting the elements somewhere).
Adding my code which works so far. I'm not sure how stable this code and how safe to use such hacks. To avoid calling copy-construct I have to call reserve
IndexesStorage::IndexesStorage(void)
{
oneItemIndexes.reserve(Instrument::InstrumentsCount());
for (int i = 0; i < Instrument::InstrumentsCount(); i++) {
oneItemIndexes.emplace_back(i);
}
}
OneItemIndex::OneItemIndex(OneItemIndex& rhs):
CustomIndex("blabla")
{
printf("OneItemIndex copy-construct must not be called, we make it public cause MSVC++ implementation!");
exit(0);
}
I'm getting an error on the insert() part here, and I dunno what I am doing wrong. I've tried different parameters and number of parameters but nothing seems to work.
m_oGameObjectList is a deque of IGameObjects (base class).
m_sPosition is a struct with 3 ints (X, Y, Z).
gameObject is the reference to an object derived from IGameObject.
for (int i = 0; i < m_oGameObjectList.size(); i++)
{
if (gameObject.m_sPosition.Z > m_oGameObjectList[i].m_sPosition.Z)
{
m_oGameObjectList.insert(i, gameObject);
i = m_oGameObjectList.size();
}
}
insert takes an iterator. Use:
m_oGameObjectList.insert(m_oGameObjectList.begin() + i, gameObject);
You'll also need to use pointers in your deque, right now you're slicing - inserting a copy of the IGameObject part of gameObject
Your call to insert should pass an iterator (not an integer index) into the deque. One way you can convert an integer index to a deque iterator is via:
my_deque_iterator iter = m_oGameObjectList.begin();
std::advance(m_oGameObjectList, i);
... though there are several other solutions that work equally well.
You can also use deque functions like push_back and push_front which just take the object you want to put at the front or back of the deque, respectively.
trying to insert an object derived from IGameObject into a deque<IGameObject> won't work as the deque is trying to store a copy of the object in the reference, not the reference itself.
Most of the time, if your trying to store an class hiearchy into a container, you do so by having the container of pointers to the base class.
It's been a while since I programmed in C++, and after coming from python, I feel soooo in a straight jacket, ok I'm not gonna rant.
I have a couple of functions that act as "pipes", accepting a list as input, returning another list as output (based on the input),
this is in concept, but in practice, I'm using std::vector to represent the list, is that acceptable?
further more, I'm not using any pointers, so I'm using std::vector<SomeType> the_list(some_size); as the variable, and returning it directly, i.e. return the_list;
P.S. So far it's all ok, the project size is small and this doesn't seem to affect performance, but I still want to get some input/advice on this, because I feel like I'm writing python in C++.
The only thing I can see is that your forcing a copy of the list you return. It would be more efficient to do something like:
void DoSomething(const std::vector<SomeType>& in, std::vector<SomeType>& out)
{
...
// no need to return anything, just modify out
}
Because you pass in the list you want to return, you avoid the extra copy.
Edit: This is an old reply. If you can use a modern C++ compiler with move semantics, you don't need to worry about this. Of course, this answer still applies if the object you are returning DOES NOT have move semantics.
If you really need a new list, I would simply return it. Return value optimization will take care of no needless copies in most cases, and your code stays very clear.
That being said, taking lists and returning other lists is indeed python programming in C++.
A, for C++, more suitable paradigm would be to create functions that take a range of iterators and alter the underlying collection.
e.g.
void DoSomething(iterator const & from, iterator const & to);
(with iterator possibly being a template, depending on your needs)
Chaining operations is then a matter of calling consecutive methods on begin(), end().
If you don't want to alter the input, you'd make a copy yourself first.
std::vector theOutput(inputVector);
This all comes from the C++ "don't pay for what you don't need" philosophy, you'd only create copies where you actually want to keep the originals.
I'd use the generic approach:
template <typename InIt, typename OutIt>
void DoMagic(InIt first, InIt last, OutIt out)
{
for(; first != last; ++first) {
if(IsCorrectIngredient(*first)) {
*out = DoMoreMagic(*first);
++out;
}
}
}
Now you can call it
std::vector<MagicIngredients> ingredients;
std::vector<MagicResults> result;
DoMagic(ingredients.begin(), ingredients.end(), std::back_inserter(results));
You can easily change containers used without changing the algorithm used, also it is efficient there's no overhead in returning containers.
If you want to be really hardcore, you could use boost::tuple.
tuple<int, int, double> add_multiply_divide(int a, int b) {
return make_tuple(a+b, a*b, double(a)/double(b));
}
But since it seems all your objects are of a single, non-polymorphic type, then the std::vector is all well and fine.
If your types were polymorphic (inherited classes of a base class) then you'd need a vector of pointers, and you'd need to remember to delete all the allocated objects before throwing away your vector.
Using a std::vector is the preferably way in many situations. Its guaranteed to use consecutive memory and is therefor pleasant for the L1 cache.
You should be aware of what happends when your return type is std::vector. What happens under the hood is that the std::vector is recursive copied, so if SomeType's copy constructor is expensive the "return statement" may be a lengthy and time consuming operation.
If you are searching and inserting a lot in your list you could look at std::set to get logarithmic time complexity instead of linear. (std::vectors insert is constant until its capacity is exceeded).
You are saying that you have many "pipe functions"... sounds like an excellent scenario for std::transform.
Another problem with returning a list of objects (opposed to working on one or two lists in place, as BigSandwich pointed out), is if your objects have complex copy constructors, those will called for each element in the container.
If you have 1000 objects each referencing a hunk of memory, and they copy that memory on Object a, b; a=b; that's 1000 memcopys for you, just for returning them contained in a container. If you still want to return a container directly, think about pointers in this case.
It works very simple.
list<int> foo(void)
{
list<int> l;
// do something
return l;
}
Now receiving data:
list<int> lst=foo();
Is fully optimal because compiler know to optimize constructor of lst well. and
would not cause copies.
Other method, more portable:
list<int> lst;
// do anything you want with list
lst.swap(foo());
What happens: foo already optimized so there is no problem to return the value. When
you call swap you set value of lst to new, and thus do not copy it. Now old value
of lst is "swapped" and destructed.
This is the efficient way to do the job.
I have this data structure Seq which inherits the class vector but has some extra functionalities.
Using this data structure Seq I have this predefined data structure:
typedef Seq< vector<int> > MxInt2d;
I want now to have a vector of several components of type MxInt2d;
I was thinking about something like:
MxInt2d* loops;
it is just that I think I have to initialize this vector and I do not have a constructor for it. should I write a constructor in order to initialize it ?
So if on one hand I would have the declaration of the following data structure:
MxInt2d myEdges_;
which is then initialized.
And on the other hand the declaration of my variable loops:
vector<MxInt2d> loops;
If I want to copy in loops[0] the first 5 elements of myEdges_, I would use the syntax:
for (int i=0;i<5;i++)
loops[0].push_back(myEdges_[i]);
The program gets compiled but when I run it I obtain a bus error message..
The same stuff happens if I use the initialization for a second loop:
for (int i=0;i<5;i++){
loops[1].push_back(myEdges_[i]);
}
(sorry for my bad judgement, I am really new with vector)
madalina
Before getting into your problem-- an observation:
Are you inheriting the vector ? Deriving vector is not a good idea. All the the standard STL containers, lacks a virtual destructor, and publicly inheriting from classes without virtual destructors is a major C++ no-no.
Don't use pointers, unless you have to. Use vector again:
vector<MxInt2d> loops;
Right now, the loops container is empty (i.e. there are no matrices inside). If you want it to contain 2 MxInt2d object, you'll either have to insert them or initialize loops differently:
// loops will contain two empty MxInt2d objects
vector<MxInt2d> loops(2);
// after the following command,
// loops will contain 3 MxInt3d objects
loops.push_back(MxInt2d());
Only after you've populated loops you can start populating its elements.
It's not a good idea to inherit from STL containers because they don't have virtual destructors, which can lead to underfined behaviour, if you try to delete a derived pointer through a base pointer (hope I got that right).
As it is, your data structure looks complex. By creating a pointer of it, you are making it even more complicated. It's better if you can create an array/vector of MxInt2d instead of making it a pointer.
No, not necessarily. std::vector will initialize all elements to 0, so if this is what you need, you won't have to write a custom constructor.
Arrays are evil in C++. You can use vector for almost anything that you can use array for. One common problem; that of initialization can be solved. Refer to this discussion how-to-initialize std::vector like 'C' array.
So, you can use 'vector loops;' without problems.
HTH,
You have a couple of problems here.
One, you should not derive from vector. If you need code that does custom stuff with a vector, you should write a class with your custom stuff that has-a vector, not is-a vector. For example:
class Seq
{
public:
// assorted constructors
// construct vec_ with zero elements
Seq() {};
// construct vec_ with one element
Seq(int singleItemToAdd)
: vec_(1, singleItemToAdd) {};
// construct vec_ with 'multipleItemsToAdd' elements
Seq(const int* multipleItemsToAdd, size_t numItemsToAdd)
: vec_(multipleItemsToAdd,multipleItemsToAdd+numItemsToAdd) {};
// assorted custom operations (instead of deriving from vector)
void customSeqOperation() const
{
/// your custom stuff here
: :
}
private:
vector<int> vec_;
};
Next problem, you are saying this code compiles but crashes at runtime:
vector<MxInt2d> loops;
for (int i=0;i<5;i++)
loops[0].push_back(myEdges_[i]);
If this is your essentially compete code, the reason why it crashes is because there is no element at loops[0] -- you haven't added it yet. You need to add an element to loops (which is a vector) before you can access the first one:
vector<MxInt2d> loops;
MxInt2d firstElement = getTheElement();
loops.push_back(firstElement);
for (int i=0;i<5;i++)
loops[0].push_back(myEdges_[i]);