I am trying to code an effective implementation of the following composite class:
class composite{
vector<base_class *> Vec;
//Other useful constants
public:
composite(vector<base_class*>);
//Other useful operations...
};
My question is about the constructor and instantiation of the class and in particular the object Vec. At the minute, I use the rather crude implementation outlined below. I the implementation to be memory efficient. I'm pretty much a newb with C++, so I'm not sure I have the optimal solution here...
I use polymorphism to store different derived classes in a vector, e.g.
vector<base_class *> Vec1;
Vec1.reserve(2);
class1 * C1 = new class1(....);
Vec1.push_back(C1);
class2 * C2 = new class(....);
Vec1.push_back(C2);
where class1 and class2 are derived classes of base_class. I then pass Vec1 to the constructor of composite as follows:
composite::composite(vector<base_class*> Vec1){
Vec.reserve(Vec1.size());
Vec.swap(Vec1);
//etc...
}
My feeling is that this is quite efficient on the memory, because Vec1 will be empty after the construction (it's elements have been swapped into Vec). On the other hand, it seems to be quite wasteful, as I am essentially copying the Vec1 into Vec. Is there a better way for me to do this? Can I somehow embed the vector Vec1 into composite? Thanks in advance!
First, use proper smart pointer instead of raw pointer.
Next - in the method you used, the reserve() call is totally unnecessary - swap() just swaps internal pointers.
And last - since we're in 2013, C++11 is already to be used, so the constructor should look like this:
composite::composite(std::vector<std::unique_ptr<base_class>> v)
: vec{ std::move(v) }
{
}
Why this way? Taking the parameter by value already copies it, and since you aren't going to use that copy anymore, it is safe to be moved out, which achieves the least amount of copies to initialize the member.
If you really care about whether a copy of any vector will be made or not, you should first pass the constructors argument by reference. So the "usual" implementation would look like this:
composite::composite( const vector<base_class*>& Vec1 )
: Vec( Vec1 )
{
}
This will omit already one copy. I wouldn't bother about this until you have some signs that this will cause any problem. You already did three dynamic memory allocations before, why do you care about a fourth?
Related
I have a struct in C++ like this:
struct MyStruct
{
someType v1;
someType2 v2;
someType3 v3;
someType4 f1();
std::vector<someType> myVector;
} ;
It will be very often used in forms like this:
//some process... after which a std::vector<someType> vec1 is generated
MyStruct myStruct;
myStruct.myVector = vec1;
Since vec1 is relative large. I want to know if it costs much time by doing the assignment myStruct.myVector = vec1;
Should I use a pointer to myVector in MyStruct to make it faster? And how?
Since vec1 is relative large. I want to know if it costs much time by doing the assignment
It costs time in linear proportion to the size of the vector.
Should I use a pointer to vec in MyStruct to make it faster?
Given the problem that you've described, no I would not suggest you use a pointer unless you've left out relevant details.
You could move assign the vector (since C++11), or swap it (prior to C++11). But that assumes that you don't need vec1 for anything else.
There is a fundamental difference between std::vector<someType> myVector and std::vector<someType*> myVector. The non-pointer version actually owns and stores the data. This means once the assignment is made changes to the original variable will not result in changes to your vector (deep copy).
In the pointer version, storage is external to the vector. This means that changes to the original will result in changes to your vector (shallow copy). The is another knock on effect as well.
Since storage is external to your vector, it is your responsibility to ensure that the original sticks around for longer than your vector. Otherwise bad things will happen. This can be mitigated with a std::shared_ptr but you are still aliasing the same memory.
So the question you need to ask is whether you require a shallow copy or a deep copy.
Also std::move will only save you a copy if data is stored external to the struct (like an stl-container) otherwise you will need to move a std::unique_ptr<someType> to save the copy.
Okay, so I have a large vector say
vector<vector<vector<int>>>
of 10000 by 10000 by 10000.
I have a class which has such a vector as a private member variable:
class foo {
private:
vector<vector<vector<int>>> myvector
};
I have a constructor for my class that uses pass by reference and initializer list:
foo(vector<vector<vector<int>>> &myvector_in) : myvector(myvector_in);
I want to know what's exactly happening in terms of memory usage. Is the private myvector the same as the one that was originally declared, or is it a copy.
Basically, I want to know if there are ever two version of myvector in memory.
Thank You!
Here is a fishing tip.
Fairly easy to answer yourself. Set [0][0][0] of myvector_in to a known value. Invoke the constructor and inside it also set [0][0][0] but of myvector to a different value. Once the constructor has returned, print the content of myvector_in. If it's the same as the one you original set you must conclude that the two vectors are different entities, thus one was copied into a different one. If they are the same than you can conclude they are in fact the same instances.
You could also print addresses to get a better sense of what's what.
I must point out, the memory requirement mention in your original question are in the realm of super computer, you got one?
You have a member of type vector<vector<vector<int>>> and initialize it with another vector<vector<vector<int>>>. How would it be possible not to have said data twice in memory? Thats more a matter of logic than a matter of c++.
Alternatives
You could store a pointer vector<vector<vector<int>>>* or a reference vector<vector<vector<int>>>& to the vector in an appropriate class member. Or use one of the smart pointers to do so. In any of these cases some serious thinking about memory management is a good idea.
Or you use a move constructor, which is moving the passed in vector in your member vector.
using vec = std::vector<std::vector<std::vector<int>>>;
class foo {
public:
foo() = delete;
foo(const vec&) = delete;
foo(vec&& myvector_in) : myvector(std::move(myvector_in)) {};
private:
vec myvector;
};
Of course that will render that argument passed to the constructor useless but that a trivial consequence of the not-copying you want.
You can pass your vector to that constructor if you first cast it to an rvalue using std::move:
foo my_foo(std::move(test));
The easy way of addressing this issue in C++11 (and newer) is to accept the constructor argument by value:
struct foo {
using vec=std::vector<std::vector<std::vector<int>>>; // from DrSvanHay
foo(vec v) : myvector(std::move(v)) {}
private:
vec myvector;
};
Surprisingly, this actually minimizes copies:
If the client has a vector cv;, cv gets copied into the parameter v, but that copy was necessary to have cv and foo::myvector upon completion.
If the client passes std::move(cv), cv gets moved into v and there is no copy.
If the client passes make_vector(...), the parameter v is move-initialized from the return value (or, in C++17, is the return value).
(In all these cases, v is then moved into foo::myvector, of course.)
For such case:
class A
{
//implementation
};
class B
{
public:
B();
~B();
private:
std::vector<std::shared_ptr<A>> _innerArray;
};
what should I do in the B() to create an object with valid state? Do I need to manually call default constructor for every A object in array? And do I need to do something special in ~B()? If B class is example of bad design, feel free to say how to make it better. Thanks.
Edit
So, here is a scheme of what I really need here.
So real values stored only in array of A and all other objects are for storing connections.
The easiest example - A = dot, B = Line (or curve) going via selected dots and C = a plane described by lines. Hope it makes question more exact.
To create a B object in a valid state you do not have to do anything more. You even do not have to declare and implement constructor and destructor for B. std::vector<std::shared_ptr<A>> that is a member of B will be default initialized in B's constructor which means it will not have any elements in a container yet. It will also be properly deleted in ~B thanks to std::vector and std::shared_ptr destructors.
On the other hand if you for example want to initialize it somehow (i.e. 3 values) you can use std::vector's std::initializer_list constructor in a B's constructor initialization list. For example:
class B
{
public:
B(): _innerArray{ std::make_shared<A>(),
std::make_shared<A>(),
std::make_shared<A>() } {}
~B() {}
private:
std::vector<std::shared_ptr<A>> _innerArray;
};
Remember that std::make_shared uses perfect forwarding so you pass A's constructor arguments as the function arguments and not the class object itself.
Answering your concerns about the design I would like to encourage you to first think about the exclusive ownership of members in a vector before you decide to share them.
class B
{
public:
B();
~B();
private:
std::vector<std::unique_ptr<A>> _innerArray;
};
Above implementation is more effective on many grounds. First of all it makes your design more clear on who is responsible for the lifetime of As. Next std::unique_ptr is faster because it does not demand thread safe reference counting. And last but not least it does not cost any additional memory (compared to regular C pointer) while std::shared_ptr may take tens of bytes (24-48) to store shared state data which is highly ineffective when you operate on small classes. That is why I always use std::unique_ptr as my first resort smart pointer and I only fallback to std::shared_ptr when it is really needed.
EDIT:
Answering your edit I would create 3 containers of classes A, B, C. Depending of the fact if you need them to be polymorphic or not I would store either values like that (non-polymorphic types):
std::deque<A> as;
std::deque<B> bs;
std::deque<C> cs;
or (polymorphic types):
std::vector<std::unique_ptr<A>> as;
std::vector<std::unique_ptr<B>> bs;
std::vector<std::unique_ptr<C>> cs;
in that order (as must live longer than bs and bs must live longer than cs). Then I would just have std::vector<A*> inside B class and std::vector<B*> inside C class without any smart pointers usage.
I hope that helps.
EDIT:
Changed std::vector to std::deque in the first case which allows references/pointers to container elements survive containers extensions with push_back(). However they will not survive erasing elements, sorting or other stuff.
If you do it like that, the vector has a size of zero elements, i.e. the contents are trivially properly initialized. If the vector were of positive size (e.g. after calling resize on the vector), each of the elements would be properly initialized. Since the elements are shared_ptrs, the default constructor of shared_ptr would be called, which means that you would end up with a vector of empty pointers.
If you want to copy the contents from another container, use the iterator version of the vector constructor:
B (SomeContainerTypeContainingSharedPointers container)
: _innerArray (container.begin (), container.end () ) {
}
If you do not want to initialize the vector from a container, but from somewhere else (e.g. create the objects on the fly) -- write an input iterator type yourself (i.e. kind of a "factory iterator").
The vector is empty so you don't have to do anything special in the default constructor. And you don't need to do anything in B() either. The reference count of the shared_ptrs will be decreased automatically when the vector's destructor is called.
Bt default std::shared_ptr<A> will populate inner ptr with NULL. To create smart pointer use std::make_shared:
_innerArray.push_back(std::make_shared<A>(/*constructor params here*/));
But in your example vector is empty.
The default constructor already does everything needed. You can even leave B() out without any loss.
Hy, I would like to ask a question that puzzles me.
I've a class like this:
class A {
private:
std::vector<Object*>* my_array_;
...
public
std::vector<Object*>& my_array(); // getter
void my_array(const std::vector<Object*>& other_array); // setter
};
I wanted to ask you, based on your experience, what is the correct way of implementing the setter and getter in a (possible) SAFE manner.
The first solution came to my mind is the following.
First, when I do implement the setter, I should:
A) check the input is not a referring to the data structure I already hold;
B) release the memory of ALL objects pointed by my_array_
C) copy each object pointed by other_array and add its copy to my_array_
D) finally end the function.
The getter may produce a copy of the inner array, just in case.
The questions are many:
- is this strategy overkilling?
- does it really avoid problems?
- somebody really uses it or are there better approaches?
I've tried to look for the answer to this question, but found nothing so particularly focused on this problem.
That of using smart pointers is a very good answer, i thank you both.. it seems I can not give "useful answer" to more than one so I apologize in advance. :-)
From your answers however a new doubt has raised.
When i use a vector containing unique_ptr to objects, I will have to define a deep copy constructor. Is there a better way than using an iterator to copy each element in the vector of objects, given that now we are using smart pointers?
I'd normally recommend not using a pointer to a vector as a member, but from your question it seems like it's shared between multiple instances.
That said, I'd go with:
class A {
private:
std::shared_ptr<std::vector<std::unique_ptr<Object> > > my_array_;
public
std::shared_ptr<std::vector<std::unique_ptr<Object> > > my_array(); // getter
void my_array(std::shared_ptr<std::vector<std::unique_ptr<Object> > > other_array); // setter
};
No checks necessary, no memory management issues.
If the inner Objects are also shared, use a std::shared_ptr instead of the std::unique_ptr.
I think you are overcomplicating things having a pointer to std::vector as data member; remember that C++ is not Java (C++ is more "value" based than "reference" based).
Unless there is a strong reason to use a pointer to a std::vector as data member, I'd just use a simple std::vector stored "by value".
Now, regarding the Object* pointers in the vector, you should ask yourself: are those observing pointers or are those owning pointers?
If the vector just observes the Objects (and they are owned by someone else, like an object pool allocator or something), you can use raw pointers (i.e. simple Object*).
But if the vector has some ownership semantics on the Objects, you should use shared_ptr or unique_ptr smart pointers. If the vector is the only owner of Object instances, use unique_ptr; else, use shared_ptr (which uses a reference counting mechanism to manage object lifetimes).
class A
{
public:
// A vector which owns the pointed Objects
typedef std::vector<std::shared_ptr<Object>> ObjectArray;
// Getter
const ObjectArray& MyArray() const
{
return m_myArray
}
// Setter
// (new C++11 move semantics pattern: pass by value and move from the value)
void MyArray(ObjectArray otherArray)
{
m_myArray = std::move(otherArray);
}
private:
ObjectArray m_myArray;
};
I was surprised to find out the vector::erase move elements on calling erase . I thought it would swap the last element with the "to-be-deleted" element and reduce the size by one. My first reaction was : "let's extend std::vector and over-ride erase()" . But I found in many threads like " Is there any real risk to deriving from the C++ STL containers? ", that it can cause memory leaks. But, I am not adding any new data member to vector. So there is no additional memory to be freed. Is there still a risk?
Some suggest that we should prefer composition over inheritance. I can't make sense of this advice in this context. Why should I waste my time in the "mechanical" task of wrapping every function of the otherwise wonderful std::vector class.? Inheritance indeed makes the most sense for this task - or am I missing something?
Why not just write a standalone function that does what you want:
template<typename T>
void fast_erase(std::vector<T>& v, size_t i)
{
v[i] = std::move(v.back());
v.pop_back();
}
All credit to Seth Carnegie though. I originally used "std::swap".
Delicate issue. The first guideline you're breaking is: "Inheritance is not for code reuse". The second is: "Don't inherit from standard library containers".
But: If you can guarantee, that nobody will ever use your unordered_vector<T> as a vector<T> you're good. However, if somebody does, the results may be undefined and/or horrible, regardless of how many members you have (it may seem to work perfectly but nevertheless be undefined behaviour!).
You could use private inheritance, but that would not free you from writing wrappers or pulling member functions in with lots of using statements, which would almost be as much code as composition (a bit less, though).
Edit: What I mean with using statements is this:
class Base {
public:
void dosmth();
};
class Derived : private Base {
public:
using Base::dosmth;
};
class Composed {
private:
Base base;
public:
void dosmth() {return base.dosmth(); }
};
You could do this with all member functions of std::vector. As you can see Derived is significantly less code than Composed.
The risk of inheritance is in the following example:
std::vector<something> *v = new better_vector<something>();
delete v;
That would cause problems because you deleted a pointer to a base class with no virtual destructor.
However if you always delete a pointer to your class like:
better_vector<something> *v = new better_vector<something>();
delete v;
Or don't allocate it on the heap there is no danger. just don't forget to call the parent destructor in your destructor.
I thought it would swap the last element with the "to-be-deleted"
element and reduce the size by one.
vector::erase maintains order of elements while moving last element to erased element and reduce the size by one does not. Since vector implements array, there is no O(1) way to maintain order of elements and to erase at the same time (unless you remove the last element).
If maintaining order of elements is not important than your solution is fine, otherwise, you better use other containers (for example list, which implements doubly-linked list).