It is said that the std::deque swap function takes constant time,not linear.
http://www.cplusplus.com/reference/deque/deque/swap-free/. How is that function implemented then?
All resizable standard library containers (that is, all except std::array) have to store their contents in dynamically allocated memory. That is because they can grow arbitrarily large and there's no way to store arbitrarily many objects in the fixed space occupied by the container object itself. In other words, it must be possible that container.size() > sizeof(container).
This means that the container object only stores a pointer to its contents, not the contents itself. Swapping two containers therefore means simply swapping these pointers. In extremely simplified form:
template <class T>
class Container
{
T *_begin, *_end;
friend void swap(Container &a, Container &b)
{
std::swap(a._begin, b._begin);
std::swap(a._end, b._end);
}
};
Of course, in practice, this is complicated by the presence of allocators etc., but the principle is the same.
The implementation of deque is typically hidden by using pimpl idiom (each deque holds a pointer to implementation). The pointers are then swapped. It might (also) be that the deque at least holds a pointer to its buffer, which is then swapped (with related members like size).
This post (copy and swap idiom) is related to how the swap might be implemented.
Related
For my project I need to store pointers to objects of type ComplicatedClass in an array. This array is stored in a class Storage along with other information I have omitted here.
Here's what I would like to do (which obviously doesn't work, but hopefully explains what I'm trying to achieve):
class ComplicatedClass
{
...
}
class Storage
{
public:
Storage(const size_t& numberOfObjects, const std::array<ComplicatedClass *, numberOfObjects>& objectArray)
: size(numberOfObjects),
objectArray(objectArray)
{}
...
public:
size_t size;
std::array<ComplicatedClass *, size> objectArray;
...
}
int main()
{
ComplicatedClass * object1 = new ComplicatedClass(...);
ComplicatedClass * object2 = new ComplicatedClass(...);
Storage myStorage(2, {object1, object2});
...
return 0;
}
What I am considering is:
Using std::vector instead of std::array. I would like to avoid this because there are parts of my program that are not allowed to allocate memory on the free-store. As far as I know, std::vector would have to do that. As a plus I would be able to ditch size.
Changing Storage to a class template. I would like to avoid this because then I have templates all over my code. This is not terrible but it would make classes that use Storage much less readable, because they would also have to have templated functions.
Are there any other options that I am missing?
How can I pass and store an array of variable size containing pointers to objects?
By creating the objects dynamically. Most convenient solution is to use std::vector.
size_t size;
std::array<ComplicatedClass *, size> objectArray;
This cannot work. Template arguments must be compile time constant. Non-static member variables are not compile time constant.
I would like to avoid this because there are parts of my program that are not allowed to allocate memory on the free-store. As far as I know, std::vector would have to do that.
std::vector would not necessarily require the use of free-store. Like all standard containers (besides std::array), std::vector accepts an allocator. If you implement a custom allocator that doesn't use free-store, then your requirement can be satisfied.
Alternatively, even if you do use the default allocator, you could write your program in such way that elements are inserted into the vector only in parts of your program that are allowed to allocate from the free-store.
I thought C++ had "free-store" instead of heap, does it not?
Those are just different words for the same thing. "Free store" is the term used in C++. It's often informally called "heap memory" since "heap" is a data structure that is sometimes used to implement it.
Beginning with C++11 std::vector has the data() method to access the underlying array the vector is using for storage.
And in most cases a std::vector can be used similar to an array allowing you to take advantage of the size adjusting container qualities of std::vector when you need them or using it as an array when you need that. See https://stackoverflow.com/a/261607/1466970
Finally, you are aware that you can use vectors in place of arrays,
right? Even when a function expects c-style arrays you can use
vectors:
vector<char> v(50); // Ensure there's enough space
strcpy(&v[0], "prefer vectors to c arrays");
The implementation of llvm::SmallVector<T,N> is split amongst many types:
llvm::SmallVectorBase holds 3 void*s for begin, end, and capacity.
llvm::SmallVectorTemplateCommon<T> holds the first element of the small storage, as an appropriately aligned and sized char array.
llvm::SmallVector<T,N> holds the next N-1 elements of the small storage, as an array of appropriately aligned and sized chararrays.
Why is the storage split between the two class templates, as opposed to having the most derived class (SmallVector<T,N>) simply store all N elements and pass in pointers to this storage down to the base class? That is, where currently the default constructor does:
SmallVector() : SmallVectorImpl<T>(N) { }
A hypothetical different implementation could do:
SmallVector() : SmallVectorImpl<T>(&Storage, T * sizeof(N)) { }
and SmallVectorTemplateCommon would not have the FirstEl member. What is the advantage of the implementation as it stands?
Splitting the storage avoids storing the inline capacity (or an "is small" bit) in the "size-erased" type SmallVectorImpl.
SmallVectorImpl<T> can be used to reference any SmallVector<T, N> and supports all vector operations on it. When the the underlying storage grows the pointer cannot be passed to free if it's using the inline capacity. Comparing the current storage's address to the first element of the inline capacity is convenient and saves a bit of memory in SmallVector.
I have a vector of vectors and I wish to delete myvec[i] from memory entirely, free up the room, and so on. Will .erase or .clear do the job for me? If not, what should I do?
Completely Removing The Vector
If you want to completely remove the vector at index i in your myvec, so that myvec[i] will no longer exist and myvec.size() will be one less that it was before, you should do this:
myvec.erase (myvec.begin() + i); // Note that this only works on vectors
This will completely deallocate all memories owned by myvec[i] and will move all the elements after it (myvec[i + 1], myvec[i + 2], etc.) one place back so that myvec will have one less vector in it.
Emptying But Keeping The Vector
However, if you don't want to remove the ith vector from myvec, and you just want to completely empty it while keeping the empty vector in place, there are several methods you can use.
Basic Method
One technique that is commonly used is to swap the vector you want to empty out with a new and completely empty vector, like this:
// suppose the type of your vectors is vector<int>
vector<int>().swap (myvec[i]);
This is guaranteed to free up all the memory in myvec[i], it's fast and it doesn't allocate any new heap memory or anything.
This is used because the method clear does not offer such a guarantee. If you clear the vector, it always does set its size to zero and destruct all the elements, but it might not (depending on the implementation) actually free the memory.
In C++11, you can do what you want with two function calls: (thanks for the helpful comment)
myvec[i].clear();
myvec[i].shrink_to_fit();
Generalization
You can write a small function that would work for most (probably all) STL containers and more:
template <typename T>
void Eviscerate (T & x)
{
T().swap (x);
}
which you use like this:
Eviscerate (myvec[i]);
This is obviously cleaner and more readable, not to mention more general.
In C++11, you can also use decltype to write a generic solution (independent of the type of your container and elements,) but it's very ugly and I only put it here for completeness:
// You should include <utility> for std::remove_reference
typename std::remove_reference<decltype(myvec[i])>::type().swap(myvec[i]);
My recommended method is the Eviscerate function above.
myvec.erase( myvec.begin() + i ) will remove myvec[i]
completely, calling its destructor, and freeing all of its
dynamically allocated memory. It will not reduce the memory
used directly by myvec: myvec.size() will be reduced by one,
but myvec.capacity() will be unchanged. To remove this last
residue, C++11 has myvec.shrink_to_fit(), which might remove
it; otherwise, you'll have to make a complete copy of myvec,
then swap it in:
void
shrink_to_fit( MyVecType& target )
{
MyVecType tmp( target.begin(), target.end() );
target.swap( tmp );
}
(This is basically what shring_to_fit will do under the hood.)
This is a very expensive operation, for very little real gain,
at least with regards to the removal of single elements; if you
are erasing a large number of elements, it might be worth
considering it after all of the erasures.
Finally, if you want to erase all of the elements,
myvec.clear() is exactly the same as myvec.erase() on each
element, with the same considerations described above. In this
case, creating an empty vector and swapping is a better
solution.
I have a structure which conceptually has the following
class C {/* expensive class */};
struct mapping {
std::map<std::pair<C,C>, C> the_map;
};
This is less than ideal as a large number of copies of C end up being stored. My current solution is to create a set of C and then store pointers (or iterators) in the map.
struct mapping {
std::set<C> all_Cs;
std::map<std::pair<C*, C*>, C*> the_map;
};
This should be safe as the_map will always be destructed before all_Cs so all pointers will be valid.
Copy construction can be done by copies the set and reconstructing the map but is it possible to efficiently implement move construction?
From what I understand, moving a set with the same allocator is required to be a constant operation which (I assume) forces the implementation to maintain the validity of pointers to objects in the set but I cannot find anything to back this up in the standard. Using this I should be able to implement a move constructor by simply moving both the set and the map and all of the pointers will correctly be owned by the new object.
Is this this reasoning correct and can I rely on this behaviour in a portable way?
Move construction is guaranteed to preserve the objects in the container, by Table 99 (Allocator-aware container requirements). In addition to the constant complexity requirement (which precludes reallocating the elements), the post-condition for X u(rv) states:
u shall have the same elements as rv had before this construction;
Move assignment does not give the same guarantee. It will allocate new elements if the allocator's traits tell it not to propagate the allocator, and does not explicitly state that it won't otherwise.
Recently, I have seen some Matrix and 1D array classes implemented in C++ where each individual element is wrapped as a class (e.g. Element class). Normally, we like to have containers like Matrix to contain actual elements (e.g. int) consecutive in a memory. Using a custom class for individual elements can give you some flexibility but what are the possible drawbacks?
To make it short, see the pseudo-code:
// 1st approach: Elements stored in their type.
template <class T>
class Matrix
{
T *m_data;
//..
};
// 2nd approach: Elements wrapped into a class
template<class T>
class Matrix
{
std::set<Element<T> > m_data; // or using std::vector<Element<T> > m_data
//..
}; // Element is a class representing single element of type T
what could be the implications of this second approach, specially if we need to use Matrix for large amount of data? Also, if we need to use this type with GPU programming(transfering to device memory back and forth)?
One drawback is a memory cost for each Element, which could be a performance concern in large collections. It will cost you at least a byte, probably more for the padding. The "sizeof" operator should tell you the cost.
If the class has no virtual functions, they will probably* be placed in contiguous memory with something like new Element[20] or std::vector<Element> v(20). As noted above, std::set and most other STL containers are not necessarily contiguous.
*I say "probably" because depending on the size of the actual type, the compiler might insert some padding, which you can probably control with #pragmas as needed.