I was reading about deques vs vectors, and came across its wikipedia entry, which says one of the three possible implementations of deque using dynamic arrays is:
Allocating deque contents from the center of the underlying array, and
resizing the underlying array when either end is reached. This
approach may require more frequent resizings and waste more space,
particularly when elements are only inserted at one end.
I was wondering if there are any STL (or STL-style) implementations that actually use this center-allocation strategy?
I am asking because this strategy looks rather appealing as it involves only one underlying array, and thus removes the memory dis-contiguity issue, which is probably the only major issue deque has when compared to vector. If I understand it right, this could well be a replacement for std::vector that allows O(1) pop_front (amortized) or a replacement for deque with memory-contiguity guarantees. I assume that this is at the cost of doubling the buffering space of a std::vector, which is not a major concern for my use cases.
Also, is it true that insertion/deletion in the middle of such a container would take half the time of std::vector on average?
UPDATE:
As #Lightness Races in Orbit pointed out, such a implementation will not be used under current standards because no one can benefit from the upsides per contract with STL and everyone will suffer from the downsides. A further question I have regarding the downsides is this:
Is it possible to implement a new vector or deque like container (say bivector) such that in addition to the functionality/operators of std::vector,
1) provides (amortized) constant time push_front() and pop_front() operations and
2) guarantees memory contiguity but not iterator validity after growing sizes?
I imagine with one array behind the scene, a lot of the indirection/performance issues on deque would go away.
No Standard Library (not "STL") implementation is going to bother with this, because it has the downsides you mention, and the upsides are not part of the requirement for std::deque.
Those requirements are carefully constructed, right from algorithmic complexity for various operations, through to iterator invalidation rules. There is no benefit in implementing a container in such a way that nobody can rely on that implementation's upsides.
Could the C++ committee introduce a new container in a future standard with a different name and with different constraints, which vendors could implement as you describe? Yes, they could.
Your problem is you lack that container. Start with something like this:
template<typename T>
class bi_vec {
std::unique_ptr<char[]> raw;
std::size_t first = 0;
std::size_t last = 0;
std::size_t capacity = 0;
char* raw_get( std::size_t index ) {
return &raw[index*sizeof(T)];
}
char const* raw_get( std::size_t index ) const {
return &raw[index*sizeof(T)];
}
T& get( std::size_t index ) {
return *reinterpret_cast<T*>(raw_get(index));
}
T const& get( std::size_t index ) const {
return *reinterpret_cast<T const *>(raw_get(index));
}
char* raw_before() {
if (first < 1)
grow();
--first;
return raw_get(first);
}
char* raw_after() {
if (last+1 >= capacity)
grow();
++last;
return raw_get(last-1);
}
void grow() {
std::vector new_capacity = (capacity+1)*2;
std::size_t new_first = (new_capacity - (last-first)) / 2;
std::size_t new_last = new_capacity - new_first;
std::unique_ptr<char[]> new_buff( new char[new_capacity*sizeof(T)] );
T* b = &get(0);
T* e = &get(last-first);
std::move( b, e, reinterpret_cast<T*>( &new_buff[new_first*sizeof(T)] ) );
std::swap( buff, raw );
std::swap( new_capacity, capacity );
std::swap( new_first, first );
std::swap( new_last, last );
for (T* it = b; it != e; ++it) {
it->~T();
}
}
public:
T& operator[]( std::size_t index ) { return get(index); }
T const& operator[]( std::size_t index ) const { return get(index); }
template<class... Us>
void emplace_back( Us&&...us ) {
char* a = raw_after();
new (a) T( std::forward<Us>(us) );
}
template<class... Us>
void emplace_front( Us&&...us ) {
char* a = raw_before();
new (a) T( std::forward<Us>(us) );
}
~bi_vec() {
for( std::size_t i = 0; i != last-first; ++i ) {
get(i).~T();
}
}
};
and add iterators (I'd be tempted to use boost iterator helpers, or raw pointers to start) and whatever interfaces you need. Note that the above needs work to ensure it remains exception safe.
Related
Background: this is a followup to #pari's answer to Constant-sized vector.
My type, metadata_t does not have a default constructor.
I use std::make_unique for fixed-size arrays that the size is not available in compile-time. (ie const size).
typedef std::unique_ptr<metadata_t[]> fixedsize_metadata_t;
fixedsize_metadata_t consolidate(const std::vector<metadata_t> &array) {
// note: this is run-time:
auto n = array.size();
return fixedsize_side_metadata_t(array.begin(), array.end()); // error
return fixedsize_side_metadata_t(array); // error
return std::unique_ptr<metadata_t[]>(0); // no error, but not useful
return std::unique_ptr<metadata_t[]>(n); // error
}
However, the constructor of unique_ptr<...[]> only accepts a size (integer). How do I initialise and copy my vector into my unique_ptr<[]>?
I tried std::unique_ptr<metadata_t[]>(array.size()); to prepare and then copy/populate the contents in the next step, but it shows a compile error.
Note: I use C++20 (or higher if it was available). Could make_unique_for_overwrite be useful? ( C++23 ).
Note: At first I thought generate (as in this answer) can do it, but it does not solve my problem because n is a run-time information.
The size of my vector is determined at run-time.
The whole point of this function is to convert my std::vector into a fixed-size data structure (with run-time size).
The data structure does not have to be unique_ptr<T[]>.
The old title referred to unique_ptr but I am really looking for a solution for a fixed-size data structure. So far, it is the only data structure I found as a "constant-size indexed container with size defined at runtime".
You can't initialize the elements of a unique_ptr<T[]> array with the elements of a vector<T> array when constructing the new array (UPDATE: apparently you can, but it is still not going to be a solution solved with a single statement, as you are trying to do).
You will have to allocate the T[] array first, and then copy the vector's elements into that array one at a time, eg:
typedef std::unique_ptr<metadata_t[]> fixedsize_metadata_t;
fixedsize_metadata_t consolidate(const std::vector<metadata_t> &array) {
fixedsize_metadata_t result = std::make_unique<metadata_t[]>(array.size());
std::copy(array.begin(), array.end(), result.get());
return result;
}
UPDATE: you updated your question to say that metadata_t does not have a default constructor. Well, that greatly complicates your situation.
The only way to create an array of objects that don't support default construction is to allocate an array of raw bytes of sufficient size and then use placement-new to construct the individual objects within those bytes. But now, you are having to manage not only the objects in the array, but also the byte array itself. By itself, unique_ptr<T[]> won't be able to free that byte array, so you would have to provide it with a custom deleter that frees the objects and the byte array. Which also means, you will have to keep track of how many objects are in the array (something new[] does for you so delete[] works, but you can't access that counter, so you will need your own), eg:
struct metadata_arr_deleter
{
void operator()(metadata_t *arr){
size_t count = *(reinterpret_cast<size_t*>(arr)-1);
for (size_t i = 0; i < count; ++i) {
arr[i]->~metadata_t();
}
delete[] reinterpret_cast<char*>(arr);
}
};
typedef std::unique_ptr<metadata_t[], metadata_arr_deleter> fixedsize_metadata_t;
fixedsize_metadata_t consolidate(const std::vector<metadata_t> &array) {
const auto n = array.size();
const size_t element_size = sizeof(std::aligned_storage_t<sizeof(metadata_t), alignof(metadata_t)>);
auto raw_bytes = std::make_unique<char[]>(sizeof(size_t) + (n * element_size));
size_t *ptr = reinterpret_cast<size_t*>(raw_bytes.get());
*ptr++ = n;
auto *uarr = reinterpret_cast<metadata_t*>(ptr);
size_t i = 0;
try {
for (i = 0; i < n; ++i) {
new (&uarr[i]) metadata_t(array[i]);
}
}
catch (...) {
for (size_t j = 0; j < i; ++j) {
uarr[j]->~metadata_t();
}
throw;
}
raw_bytes.release();
return fixedsize_metadata_t(uarr);
}
Needless to say, this puts much more responsibility on you to allocate and free memory correctly, and it is really just not worth the effort at this point. std::vector already supports everything you need. It can create an object array using a size known at runtime, and it can create non-default-constructable objects in that array, eg.
std::vector<metadata_t> consolidate(const std::vector<metadata_t> &array) {
auto n = array.size();
std::vector<metadata_t> varr;
varr.reserve(n);
for (const auto &elem : array) {
// either:
varr.push_back(elem);
// or:
varr.emplace_back(elem);
// it doesn't really matter in this case, since they
// will both copy-construct the new element in the array
// from the current element being iterated...
}
return varr;
}
Which is really just a less-efficient way of avoiding the vector's own copy constructor:
std::vector<metadata_t> consolidate(const std::vector<metadata_t> &array) {
return array; // will return a new copy of the array
}
The data structure does not have to be unique_ptr<T[]>. The old title referred to unique_ptr but I am really looking for a solution for a fixed-size data structure. So far, it is the only data structure I found as a "constant-size indexed container with size defined at runtime".
What you are looking for is exactly what std::vector already gives you. You just don't seem to realize it, or want to accept it. Both std::unique_ptr<T[]> and std::vector<T> hold a pointer to a dynamically-allocated array of a fixed size specified at runtime. It is just that std::vector offers more functionality than std::unique_ptr<T[]> does to manage that array (for instance, re-allocating the array to a different size). You don't have to use that extra functionality if you don't need it, but its base functionality will suit your needs just fine.
Initializing an array of non-default constructibles from a vector is tricky.
One way, if you know that your vector will never contain more than a certain amount of elements, could be to create an index_sequence covering all elements in the vector. There will be one instantiation of the template for each number of elements in your vector that you plan to support and the compilation time will be "silly".
Here I've selected the limit 512. It must have a limit, or else the compiler will spin in endless recursion until it gives up or crashes.
namespace detail {
template <class T, size_t... I>
auto helper(const std::vector<T>& v, std::index_sequence<I...>) {
if constexpr (sizeof...(I) > 512) { // max 512 elements in the vector.
return std::unique_ptr<T[]>{}; // return empty unique_ptr or throw
} else {
// some shortcuts to limit the depth of the call stack
if(sizeof...(I)+255 < v.size())
return helper(v, std::make_index_sequence<sizeof...(I)+256>{});
if(sizeof...(I)+127 < v.size())
return helper(v, std::make_index_sequence<sizeof...(I)+128>{});
if(sizeof...(I)+63 < v.size())
return helper(v, std::make_index_sequence<sizeof...(I)+64>{});
if(sizeof...(I)+31 < v.size())
return helper(v, std::make_index_sequence<sizeof...(I)+32>{});
if(sizeof...(I)+15 < v.size())
return helper(v, std::make_index_sequence<sizeof...(I)+16>{});
if(sizeof...(I)+7 < v.size())
return helper(v, std::make_index_sequence<sizeof...(I)+8>{});
if(sizeof...(I)+3 < v.size())
return helper(v, std::make_index_sequence<sizeof...(I)+4>{});
if(sizeof...(I)+1 < v.size())
return helper(v, std::make_index_sequence<sizeof...(I)+2>{});
if(sizeof...(I) < v.size())
return helper(v, std::make_index_sequence<sizeof...(I)+1>{});
// sizeof...(I) == v.size(), create the pointer:
return std::unique_ptr<T[]>(new T[sizeof...(I)]{v[I]...});
}
}
} // namespace detail
template <class T>
auto make_unique_from_vector(const std::vector<T>& v) {
return detail::helper(v, std::make_index_sequence<0>{});
}
You can then turn your vector into a std::unique_ptr<metadata_t[]>:
auto up = make_unique_from_vector(foos);
if(up) {
// all is good
}
Demo (compilation time may exceed the time limit)
You have to allocate some uninitialized memory for an array and copy construct the elements in-place using construct_at. You can then create a unique_ptr using the address of the constructed array:
#include <vector>
#include <memory>
struct metadata_t {
metadata_t(int) { }
};
typedef std::unique_ptr<metadata_t[]> fixedsize_metadata_t;
fixedsize_metadata_t consolidate(const std::vector<metadata_t> &array) {
// note: this is run-time:
auto n = array.size();
std::allocator<metadata_t> alloc;
metadata_t *t = alloc.allocate(n);
for (std::size_t i = 0; i < array.size(); ++i) {
std::construct_at(&t[i], array[i]);
}
return fixedsize_metadata_t(t);
}
I am interfacing with some C++ code that has a method providing a pointer and object size (some proprietary library that I can't change). The interface looks something like this:
float *arrayPtr();
int arraySize();
I have a class that needs to copy this to a vector (in order to extend its lifetime). In the scenario where this pointer is not a nullptr, the constructor is fairly simple (I need to copy the data to extend its lifetime):
struct A {
std::vector<float> vec;
A(float *ptr, int size) : vec( ptr, std::next(ptr, size) ) {}
}
I am, however, a little unsure of how best to handle the initialization when ptr is a nullptr. I could default initialize, and then move everything to the constructor body, but that feels quite inefficient:
A(float *ptr, int size) {
if (ptr) {
vec = std::vector<float>( ptr, std::next(ptr, size));
}
}
Are there any other alternatives?
When ptr is a nullptr, I would like the vector to just be default initialized to an empty vector.
EDIT:
It just occurred to me that I should probably be doing this:
A(float *ptr, int size) : vec( ptr ? std::vector<float>(ptr, std::next(ptr, size)) : std::vector<float>() ) {}
But perhaps there is a better form??
This is not necessarily "better" (actually I think your original code is fine, since there is not really any cost to default initialization of a vector), but when you need to perform some logic for an initializer you can use a helper function:
struct A {
std::vector<float> vec;
A(float *ptr, int size) : vec( make_A_vector(ptr, size) ) {}
private:
static std::vector<float> make_A_vector(float const *begin, int size)
{
if ( size < 0 || (size > 0 && !begin) )
throw std::runtime_error("invalid array length for A");
if ( size == 0 )
return {};
return std::vector<float>(begin, begin + size);
}
};
Another common design is to keep your class simple and have construction logic entirely in a free function:
struct A
{
std::vector<float> vec;
};
inline A make_A(float const *ptr, int size)
{
// sanity check omitted for brevity
if ( size == 0 )
return A{};
return A{ std::vector<float>(ptr, ptr + size) };
}
It's an experience-based judgement call as to what would be overkill and what would be aesthetic :)
Researching what std::next and the ctor of std::vector is doing. your first try works just fine. ONLY and ONLY if your size is reliably 0, when your pointer is a nullptr.
std::next(it, n)
it - Iterator to base position. ForwardIterator shall be at least a
forward iterator.
n - Number of element positions offset (1 by default).
This shall only be negative for random-access and bidirectional
iterators. difference_type is the numerical type that represents
distances between iterators of the ForwardIterator type.
If you are assured, your given size is 0, when you get a nullptr, std::next returns the same position as your pointer points to.
std::vector
You use this ctor:
Constructs the container with the contents of the range [first, last).
If your first and last are the same, you get an empty std::vector. So the nullptr is never a problem.
Regardless this findings. you should ALWAYS check for nullptr's. For the sake of defensive programming - ALL INPUT IS EVIL!
You mentioned, the library you get is known for being error prone. Please save yourself much troubles and check every parameter you get out of it of integrity.
One comment on your worries that your implementation would perform any worse then an other. Check those implementations in an loop with thousands or millions of iterations. Then you can make an prediction if it effects you.
I have an std::map, and I use the following method for filling up to the maximum value of the supplied data type. In this case, if K is int then the maximum value is 2,147,483,647. I want my map to have 2,147,483,647 keys with the same value.
The below loop is very inefficient. Is there any method to reduce the time consumption?
for (auto i = keyBegin; i!=numeric_limits<K>::max(); i++) {
m_map[i] = val;
}
The problem with the code above is that you're inserting 2 billion numbers, all at the end of the map. But operator[] has no idea that you'll be inserting a new item there!
std::map::insert(hint_before, value) is what you need. You've got a perfect hint - all values will be inserted directly before m_map.end()
To supplement the existing answers, this is really not a good use of std::map.
Maps are designed for quick lookup in a collection of keys & values, where the keys are "sparse". They're generally implemented as trees, requiring lots of dynamic allocation, tree rebalancing, and the sacrifice of cache locality. This is worth it for the general map use case.
But your keys are far from sparse! You literally have a value for every possible number in the key's type's range. This is what arrays are for.
Use an array and you will benefit from cache, you will benefit from constant-time lookups, and you will not need any dynamic allocation inside the container. You will of course need to dynamically allocate the container itself because it is huge, so, you're looking for std::vector.
And that's only if you really need to precalculate all these values. If you don't necessarily need them all multiple times, consider generating them on-demand instead. Because, regardless how much RAM a contemporary PC can provide you, this feels a bit like an abuse of the technology.
To supplement MSalters's answer, that suggests to use map::insert(hint, {key, value}) construct, I suggest to use a non-default allocator. A specialized allocater can further speed up the insertion twofold. Consider the following trivial allocator:
template <class T>
class chunk_allocator
{
private:
struct node
{
union
{
node *next;
char element[sizeof(T)];
};
};
public:
using value_type = T;
using size_type = std::size_t;
using difference_type = std::ptrdiff_t;
using is_always_equal = std::false_type;
using propagate_on_container_move_assignment = std::true_type;
T*allocate(std::size_t n)
{
if (n > 1)
return reinterpret_cast<T*>(::operator new(sizeof(T) * n));
if (!m_free_head) populate();
node * head = m_free_head;
m_free_head = head->next;
using node_ptr = node*;
head->next.~node_ptr();
return reinterpret_cast<T*>(&head->element);
}
void deallocate(T* p, std::size_t n) {
if (!p)
return;
if (n > 1) {
::operator delete((void*)p);
return;
}
node * new_head = new ((void*)p) node;
new_head->next = m_free_head;
m_free_head = new_head->next;
}
private:
static constexpr unsigned NODES_IN_CHUNK = 1000;
void populate()
{
if (m_free_head) return;
m_chunks.emplace_back();
for (node & entry : m_chunks.back()) {
entry.next = m_free_head;
m_free_head = &entry;
}
}
std::list<std::array<node, NODES_IN_CHUNK>> m_chunks;
node * m_free_head = nullptr;
};
template< class T1, class T2 >
bool operator==( const chunk_allocator<T1>& a, const chunk_allocator<T2>& b )
{
return (void*)&a == (void*)&b;
}
template< class T1, class T2 >
bool operator!=( const chunk_allocator<T1>& a, const chunk_allocator<T2>& b )
{
return !(a == b);
}
And its use:
std::map<int, int, std::less<int>,
chunk_allocator<std::pair<const int, int >>> m_map;
Working 100,000,000 elements takes (on windows with cygwin):
std::allocator: Insertion: 7.987, destruction: 7.238
chunk_allocator: Insertion: 2.745, destruction: 1.357
On Linux the differences are not that big, but still 2x improvements are possible.
Bonus points - the chunk_allocator takes less memory, since it does not use operator new for individual map nodes. Each call to operator new has to maintain memory management bookkeeping, which chunk_allocator does not have to.
As my usually used C++ compilers allow variable-length arrays (e.g. arrays depending on runtime size), I wonder if there is something like std::array with variable size? Of course std::vector is of variable size, but it allocates on heap, and reallocates on need.
I like to have a stack allocated array with size defined at runtime. Is there any std-template that may feature this? Maybe using std::vector with a fixed maximum size?
There are two proposals currently being worked on to bring run-time fixed size arrays to C++ which may be of interest to you:
Runtime-sized arrays with automatic storage duration. This would make runtime sized arrays a language feature (like in C11). So you could do:
void foo(std::size_t size) {
int arr[size];
}
C++ Dynamic Arrays. This would bring a new container to the library, std::dynarray, which is given a fixed size at construction. It is intended to be optimized to be allocated on the stack when possible.
void foo(std::size_t size) {
std::dynarray<int> arr(size);
}
These are both being worked on as part of an Array Extensions Technical Specification, which will be released alongside C++14.
UPDATE: std::dynarray is not implemented yet(25Aug2021).please refer to What is the status on dynarrays?
As Daniel stated in the comment, size of the std::array is specified as a template parameter, so it cannot be set during runtime.
You can though construct std::vector by passing the minimum capacity through the constructor parameter:
#include <vector>
int main(int argc, char * argv[])
{
std::vector<int> a;
a.reserve(5);
std::cout << a.capacity() << "\n";
std::cout << a.size();
getchar();
}
But. Still vector's contents will be stored on the heap, not on the stack. The problem is, that compiler has to know, how much space should be allocated for the function prior to its execution, so it is simply not possible to store variable-length data on the stack.
Maybe using std::vector with a fixed maximal size?
If boost is allowed then boost::container::static_vector and boost::container::small_vector are the closest I can think of
boost::container::static_vector<int, 1024> my_array;
boost::container::small_vector<int, 1024> my_vector;
static_vector is a sequence container like boost::container::vector with contiguous storage that can change in size, along with the static allocation, low overhead, and fixed capacity of boost::array.
The size of each object is still fixed but it can be worth it if the number of allocations is significant and/or the item count is small
If the vector can grow beyond the limit then just use boost::container::small_vector. The heap is only touched when the size is larger than the defined limit
small_vector is a vector-like container optimized for the case when it contains few elements. It contains some preallocated elements in-place, which can avoid the use of dynamic storage allocation when the actual number of elements is below that preallocated threshold.
If you use Qt then QVarLengthArray is another way to go:
QVarLengthArray is an attempt to work around this gap in the C++ language. It allocates a certain number of elements on the stack, and if you resize the array to a larger size, it automatically uses the heap instead. Stack allocation has the advantage that it is much faster than heap allocation.
Example:
int myfunc(int n)
{
QVarLengthArray<int, 1024> array(n + 1);
...
return array[n];
}
Some other similar solutions:
llvm::SmallVector
Facebook's folly::small_vector
Electronic Arts Standard Template Library's eastl::fixed_vector
If a 3rd party solution isn't allowed then you can roll your own solution by wrapping std::array in a struct to get a static vector
template<typename T, size_t N>
struct my_static_vector
{
explicit static_vector(size_t size) { } // ...
size_t size() const noexcept { return curr_size; }
static size_t capacity() const noexcept { return N; }
T& operator[](size_t pos) { return data[pos]; }
void push_back(const T& value) { data[curr_size++] = value; }
// ...
private:
std::array<typename T, N> data;
std::size_t curr_size;
}
And if small_vector is required then you can use std::variant to contain both the my_static_vector and the vector
template<typename T, size_t N>
struct my_small_vector
{
explicit small_vector(size_t size) { } // ...
size_t size() const noexcept {
if (data.index() == 0) {
return data.get<0>().size();
} else {
return data.get<1>().size();
}
}
static size_t capacity() const noexcept {
if (data.index() == 0) {
return data.get<0>().capacity();
} else {
return data.get<1>().capacity();
}
}
// ...
private:
std::variant<my_static_vector<T, N>, std::vector<T>> data;
}
Not entirely a question, although just something I have been pondering on how to write such code more elegantly by style and at the same time fully making use of the new c++ standard etc. Here is the example
Returning Fibonacci sequence to a container upto N values (for those not mathematically inclined, this is just adding the previous two values with the first two values equal to 1. i.e. 1,1,2,3,5,8,13, ...)
example run from main:
std::vector<double> vec;
running_fibonacci_seq(vec,30000000);
1)
template <typename T, typename INT_TYPE>
void running_fibonacci_seq(T& coll, const INT_TYPE& N)
{
coll.resize(N);
coll[0] = 1;
if (N>1) {
coll[1] = 1;
for (auto pos = coll.begin()+2;
pos != coll.end();
++pos)
{
*pos = *(pos-1) + *(pos-2);
}
}
}
2) the same but using rvalue && instead of & 1.e.
void running_fibonacci_seq(T&& coll, const INT_TYPE& N)
EDIT: as noticed by the users who commented below, the rvalue and lvalue play no role in timing - the speeds were actually the same for reasons discussed in the comments
results for N = 30,000,000
Time taken for &:919.053ms
Time taken for &&: 800.046ms
Firstly I know this really isn't a question as such, but which of these or which is best modern c++ code? with the rvalue reference (&&) it appears that move semantics are in place and no unnecessary copies are being made which makes a small improvement on time (important for me due to future real-time application development). some specific ''questions'' are
a) passing a container (which was vector in my example) to a function as a parameter is NOT an elegant solution on how rvalue should really be used. is this fact true? if so how would rvalue really show it's light in the above example?
b) coll.resize(N); call and the N=1 case, is there a way to avoid these calls so the user is given a simple interface to only use the function without creating size of vector dynamically. Can template metaprogramming be of use here so the vector is allocated with a particular size at compile time? (i.e. running_fibonacci_seq<30000000>) since the numbers can be large is there any need to use template metaprogramming if so can we use this (link) also
c) Is there an even more elegant method? I have a feeling std::transform function could be used by using lambdas e.g.
void running_fibonacci_seq(T&& coll, const INT_TYPE& N)
{
coll.resize(N);
coll[0] = 1;
coll[1] = 1;
std::transform (coll.begin()+2,
coll.end(), // source
coll.begin(), // destination
[????](????) { // lambda as function object
return ????????;
});
}
[1] http://cpptruths.blogspot.co.uk/2011/07/want-speed-use-constexpr-meta.html
Due to "reference collapsing" this code does NOT use an rvalue reference, or move anything:
template <typename T, typename INT_TYPE>
void running_fibonacci_seq(T&& coll, const INT_TYPE& N);
running_fibonacci_seq(vec,30000000);
All of your questions (and the existing comments) become quite meaningless when you recognize this.
Obvious answer:
std::vector<double> running_fibonacci_seq(uint32_t N);
Why ?
Because of const-ness:
std::vector<double> const result = running_fibonacci_seq(....);
Because of easier invariants:
void running_fibonacci_seq(std::vector<double>& t, uint32_t N) {
// Oh, forgot to clear "t"!
t.push_back(1);
...
}
But what of speed ?
There is an optimization called Return Value Optimization that allows the compiler to omit the copy (and build the result directly in the caller's variable) in a number of cases. It is specifically allowed by the C++ Standard even when the copy/move constructors have side effects.
So, why passing "out" parameters ?
you can only have one return value (sigh)
you may wish the reuse the allocated resources (here the memory buffer of t)
Profile this:
#include <vector>
#include <cstddef>
#include <type_traits>
template <typename Container>
Container generate_fibbonacci_sequence(std::size_t N)
{
Container coll;
coll.resize(N);
coll[0] = 1;
if (N>1) {
coll[1] = 1;
for (auto pos = coll.begin()+2;
pos != coll.end();
++pos)
{
*pos = *(pos-1) + *(pos-2);
}
}
return coll;
}
struct fibbo_maker {
std::size_t N;
fibbo_maker(std::size_t n):N(n) {}
template<typename Container>
operator Container() const {
typedef typename std::remove_reference<Container>::type NRContainer;
typedef typename std::decay<NRContainer>::type VContainer;
return generate_fibbonacci_sequence<VContainer>(N);
}
};
fibbo_maker make_fibbonacci_sequence( std::size_t N ) {
return fibbo_maker(N);
}
int main() {
std::vector<double> tmp = make_fibbonacci_sequence(30000000);
}
the fibbo_maker stuff is just me being clever. But it lets me deduce the type of fibbo sequence you want without you having to repeat it.