I use a C library which operates on 2D arrays in the form of Foo**. I use it inside C++ code, so I need some sort of wrapper. With 1D arrays it's straightforward because vector iterators are just pointers, but in case of 2D it gets more complicated. Is it possible to make a wrapper for Foo** without copying the data?
The elements of a vector<Foo> are stored in a dynamically allocated contiguous memory, so you can get a pointer Foo* to the array, as you do in your first case.
But the elements of a nested vector vector<vector<Foo> > are not stored as a contiguous 2D array, so you can't get a Foo** directly.
You could try something like this :
vector<vector<Foo> > data;
vector<Foo*> data_rows;
for(auto it = data.begin(); it != data.end(); ++it) {
//in c++11, you can use data() instead of casting begin()
data_rows.push_back(it->data());
}
Foo** c_data = data_rows.data();
That way you're not copying the data, just the row pointers.
I would propose to build a class overriding operator [], which holds the C pointer Foo** internally.
E.g.:
template <class T>
class Mat<T> {
private: T** ptr; int n; int m; //< 2D array is of size n x m
public: Mat( int n, int m ) : n(n), m(m) {}
Col<T> operator[]( int k ) { assert(k<n); return Col<T>(*(ptr+k*n)); }
T& get(int k, int i ) { return *(*(ptr+k*n)+i); }
}
having defined
template <class T>
class Col<T> { private: T* ptr;
public: T& operator[]( int i ) { return *(ptr+i); }
Col<T>(T* ptr) : ptr(ptr) { }
}
The code may not be 100% correct, but i hope you get the point and can reimplement it.
Also make sure livetime of pointerdata exceeds your c++ wrapper (also wrap the refcount mechanism of the c library?).
The nice point of operator[] is, that now you can use it like that:
Foo** ptr = from_some_c_library();
Mat<Foo> mat(ptr,3,4);
Foo& element_at_2_2 = mat[2][2];
assert( mat.get(2,2) == mat[2][2] );
Note that you may want to implement custom iterators for Mat<T> to make it work with STL functions.
Related
I need a container with run-time known size with no need to resizing. std::unique_ptr<T[]> would be a useful, but there is no encapsulated size member. In the same time std::array is for compile type size only. Hence I need some combination of these classes with no/minimal overhead.
Is there a standard class for my needs, maybe something in upcoming C++20?
Use std::vector. This is the class for runtime sized array in the STL.
It let you resize it or pushing elements into it:
auto vec = std::vector<int>{};
vec.resize(10); // now vector has 10 ints 0 initialized
vec.push_back(1); // now 11 ints
Some problems stated in the comments:
vector has an excessive interface
So is std::array. You have more than 20 function in std::array including operators.
Just don't use what you don't need. You don't pay for the function you won't use. It won't even increase your binary size.
vector will force initialize items on resize. As far as I know, it is not allowed to use operator[] for indexes >= size (despite calling reserve).
This is not how it is meant to be used. When reserving you should then resize the vector with resize or by pushing elements into it. You say vector will force initialize elements into it, but the problem is that you cannot call operator= on unconstructed objects, including ints.
Here's an example using reserve:
auto vec = std::vector<int>{};
vec.reserve(10); // capacity of at least 10
vec.resize(3); // Contains 3 zero initialized ints.
// If you don't want to `force` initialize elements
// you should push or emplace element into it:
vec.emplace_back(1); // no reallocation for the three operations.
vec.emplace_back(2); // no default initialize either.
vec.emplace_back(3); // ints constructed with arguments in emplace_back
Keep in mind that there is a high chance for such allocation and use case, the compiler may completely elide construction of elements in the vector. There may be no overhead in your code.
I would suggest to measure and profile if your code is subject to very precise performance specification. If you do not have such specification, most likely this is premature optimization. The cost of memory allocation completely out measure the time it takes to initialize elements one by one.
Other parts of your program may be refactored to gain much more performance than trivial initialization can offer you. In fact, getting in the way of it may hinder optimization and make your program slower.
Allocate the memory using an std::unique_ptr<T[]> like you suggested, but to use it - construct an std::span (in C++20; gsl::span before C++20) from the raw pointer and the number of elements, and pass the span around (by value; spans are reference-types, sort of). The span will give you all the bells and whistles of a container: size, iterators, ranged-for, the works.
#include <span>
// or:
// #include <gsl/span>
int main() {
// ... etc. ...
{
size_t size = 10e5;
auto uptr { std::make_unique<double[]>(size) };
std::span<int> my_span { uptr.get(), size };
do_stuff_with_the_doubles(my_span);
}
// ... etc. ...
}
For more information about spans, see:
What is a "span" and when should I use one?
Use std::vector. If you want to remove the possibility of changing it's size, wrap it.
template <typename T>
single_allocation_vector : private std::vector<T>, public gsl::span<T>
{
single_allocation_vector(size_t n, T t = {}) : vector(n, t), span(vector::data(), n) {}
// other constructors to taste
};
Something called std::dynarray was proposed for C++14:
std::dynarray is a sequence container that encapsulates arrays with a size that is fixed at construction and does not change throughout the lifetime of the object.
But there were too many issues and it didn't become part of the standard.
So there exists no such container currently in the STL. You can keep using vectors with an initial size.
Unfortunately, no new containers were added in C++ 20 (at least none that I'd be aware of). I would agree, however, that such a container would be very useful. While just using std::vector<T> with reserve() and emplace_back() will usually do OK, it does often generate inferior code compared to using a plain new T[] as the use of emplace_back() seems to inhibit vectorization. If we use an std::vector<T> with an initial size instead, compilers seem to have trouble optimizing away the value initialization of elements, even if the entire vector is going to be overwritten right afterwards. Play with an example here.
You could use, for example, a wrapper like
template <typename T>
struct default_init_wrapper
{
T t;
public:
default_init_wrapper() {}
template <typename... Args>
default_init_wrapper(Args&&... args) : t(std::forward<Args>(args)...) {}
operator const T&() const { return t; }
operator T&() { return t; }
};
and
std::vector<no_init_wrapper<T>> buffer(N);
to avoid the useless initialization for trivial types. Doing so seems to lead to code similarly good as the plain std::unique_ptr version. I wouldn't recommend this though, as it's quite ugly and cubmersome to use, since you then have to work with a vector of wrapped elements.
I guess the best option for now is to just roll your own container. This may serve as a starting point (beware of bugs):
template <typename T>
class dynamic_array
{
public:
using value_type = T;
using reference = T&;
using const_reference = T&;
using pointer = T*;
using const_pointer = const T*;
using iterator = T*;
using const_iterator = const T*;
using reverse_iterator = std::reverse_iterator<iterator>;
using const_reverse_iterator = std::reverse_iterator<const_iterator>;
using size_type = std::size_t;
using difference_type = std::ptrdiff_t;
private:
std::unique_ptr<T[]> elements;
size_type num_elements = 0U;
friend void swap(dynamic_array& a, dynamic_array& b)
{
using std::swap;
swap(a.elements, b.elements);
swap(a.num_elements, b.num_elements);
}
static auto alloc(size_type size)
{
return std::unique_ptr<T[]> { new T[size] };
}
void checkRange(size_type i) const
{
if (!(i < num_elements))
throw std::out_of_range("dynamic_array index out of range");
}
public:
const_pointer data() const { return &elements[0]; }
pointer data() { return &elements[0]; }
const_iterator begin() const { return data(); }
iterator begin() { return data(); }
const_iterator end() const { return data() + num_elements; }
iterator end() { return data() + num_elements; }
const_reverse_iterator rbegin() const { return std::make_reverse_iterator(end()); }
reverse_iterator rbegin() { return std::make_reverse_iterator(end()); }
const_reverse_iterator rend() const { return std::make_reverse_iterator(begin()); }
reverse_iterator rend() { return std::make_reverse_iterator(begin()); }
const_reference operator [](size_type i) const { return elements[i]; }
reference operator [](size_type i) { return elements[i]; }
const_reference at(size_type i) const { return checkRange(i), elements[i]; }
reference at(size_type i) { return checkRange(i), elements[i]; }
size_type size() const { return num_elements; }
constexpr size_type max_size() const { return std::numeric_limits<size_type>::max(); }
bool empty() const { return std::size(*this) == 0U; }
dynamic_array() = default;
dynamic_array(size_type size)
: elements(alloc(size)), num_elements(size)
{
}
dynamic_array(std::initializer_list<T> elements)
: elements(alloc(std::size(elements))), num_elements(std::size(elements))
{
std::copy(std::begin(elements), std::end(elements), std::begin(*this));
}
dynamic_array(const dynamic_array& arr)
{
auto new_elements = alloc(std::size(arr));
std::copy(std::begin(arr), std::end(arr), &new_elements[0]);
elements = std::move(new_elements);
num_elements = std::size(arr);
}
dynamic_array(dynamic_array&&) = default;
dynamic_array& operator =(const dynamic_array& arr)
{
return *this = dynamic_array(arr);
}
dynamic_array& operator =(dynamic_array&&) = default;
void swap(dynamic_array& arr)
{
void swap(dynamic_array& a, dynamic_array& b);
swap(*this, arr);
}
friend bool operator ==(const dynamic_array& a, const dynamic_array& b)
{
return std::equal(std::begin(a), std::end(a), std::begin(b));
}
friend bool operator !=(const dynamic_array& a, const dynamic_array& b)
{
return !(a == b);
}
};
I receive an array as a pointer from a function and want to initialize a QVector from that.
For now I do it like this:
void foo(double* receivedArray, size_t size)
{
QVector<double> vec(size);
std::copy(receivedArray, receivedArray + size, std::begin(vec));
}
Would it be equally possible to do this:
void foo(double* receivedArray, size_t size)
{
QVector<double> vec(size);
vec.data() = receivedArray;
}
Would this break some kind of Qt mechanism that I am not aware of?
The first one does unnecessary work, initializing the vector with default-constructed doubles before filling it. Unfortunately, QVector lacks a ranged-insertion, so you must resort to algorithms:
void foo(double* receivedArray, size_t size)
{
QVector<double> vec;
vec.reserve(size); // warning: size_t->int cast
std::copy(receivedArray, receivedArray + size, std::back_inserter(vec));
}
The second version does not even compile, as data() returns a T *, which is a rvalue that you can't put on the left side of an assignment.
QVector::data does not return a reference to the underlying pointer, so you cannot assign to vec.data() (it is not an lvalue, it will not even compile):
template <typename T>
struct Vector {
T* data_;
T* nref_data () { return data_; }
T* &ref_data () { return data_; }
};
Vector<int> vec;
vec.ref_data() = new int[100]; // Ok, Vector<int>::ref_data returns a reference
vec.nref_data() = new int[100]; // Nok, Vector<int>::nref_data does not return a reference
Another solution:
void foo(double* receivedArray, size_t size)
{
QVector<double> vec(receivedArray,receivedArray+size);
}
see also:
http://cpp.sh/7jfi6
Using C++, I am trying to create an array that holds pointers to objects I'm storing. But when the array is full, I want to expand the array.
the easy option is to allocate a new array with bigger size, then copy the elements to it, this is quite inefficient, and I thought of another way I want to try to do it:
create array of fixed size X
When full, create a new array, and make the end of the first array point to the start of the first element
Repeat as long as needed
What methods can I use to do that? I thought of one way to do it, but it seems very hacky:
declare all my new array as pointers to object pointer, then reinterprit_cast the filled elements to object pointer.
Note: I know I can use Vector, but I am instructed not to use std library.
Kind Regards,
There are some good answers in the comments already. I just want to provide a way to achieve exactly the behavior you described.
Since the elements of the array are pointers as well, you can define a union as the element of your array like this:
template<typename T>
union Cell
{
T* pElm;
Cell* pNext;//A fixed size array of Cells
}
And then build your array on top of it. For example:
template<typename T>
class SpecialArray
{
public:
//the next pointer is included
static const size_t ARRAY_LEN = 1000;// For example
using Pointer = T*;
using Segment = Cell<T>[ARRAY_LEN];
protected:
Segment* pFirst;
size_t mSize;
public:
SpecialArray()
:pFirst(nullptr),mSize(0){}
SpecialArray(SpecialArray&&){}
~SpecialArray(){}
Pointer& operator[](size_t index)
{
Segment* seg = pFirst;
size_t offest = 0;
//Search logic...
return seg[offest]->pElm;
}
const Pointer& operator[](size_t index) const;
};
Using C++, I am trying to create an array that holds pointers to
objects I'm storing. But when the array is full, I want to expand the
array.
With C++ templates and C primitives we can improvise a simple vector like below. And the grow buffer strategy is to double the size when the threshold is met.
#include <iostream>
#include <stdlib.h>
template <typename T>
class MyVector
{
public:
MyVector() : m_count(0), m_size(0), m_buffer(0)
{
m_size = bufInitSize;
m_buffer = (T*)malloc(sizeof(T) * bufInitSize);
}
~MyVector()
{
if (m_buffer)
free(m_buffer);
}
void add(const T& p)
{
if (m_count + 1 >= m_size)
{
m_size *= 2;
m_buffer = (T*)realloc(m_buffer, sizeof(T) * m_size);
}
m_buffer[m_count ++ ] = p;
}
T& operator[](int idx)
{
return m_buffer[idx];
}
private:
static const int bufInitSize = 1024;
T* m_buffer;
int m_count;
int m_size;
};
void main()
{
// using MyVector
MyVector<int*> vctOfIntPtr;
int n = 100;
vctOfIntPtr.add(&n);
int* pN = vctOfIntPtr[0];
std::cout << *pN;
}
OK, so I recently learned that (a) std::vector uses contiguous memory by definition/standard, and thus (b) &(v[0]) is the address of that contiguous block of memory, which you can read/write to as an old-skool C-array. Like...
void printem(size_t n, int* iary)
{ for (size_t i=0; i<n; ++i) std::cout << iary[i] << std::endl; }
void doublem(size_t n, int* iary)
{ for (size_t i=0; i<n; ++i) iary[i] *= 2; }
std::vector<int> v;
for (size_t i=0; i<100; ++i) v.push_back(i);
int* iptr = &(v[0]);
doublem(v.size(), iptr);
printem(v.size(), iptr);
OK, so that's cool, but I want to go in the other direction. I have lots and lots of existing code like
double computeSomething(const std::vector<SomeClass>& v) { ... }
If I have a C-array of objects, I can use such code like this:
SomeClass cary[100]; // 100*sizeof(SomeClass)
// populate this however
std::vector<SomeClass> v;
for (size_t i=0; i<100; ++i) v.push_back(cary[i]);
// now v is also using 100*sizeof(SomeClass)
double x = computeSomething(v);
I would like to do that (a) without the extra space and (b) without the extra time of inserting a redundant copy of all that data into the vector. Note that "just change your stupid computeSomething, idiot" is not sufficient, because there are thousands of such functions/methods that exhibit this pattern that are not under my control and, even if they were are too many to go and change all of them.
Note also that because I am only interested in const std::vector& usage, there is no worry that my original memory will ever need to be resized, or even modified. I would want something like a const std::vector constructor, but I don't know if the language even allows special constructors for const instances of a class, like:
namespace std { template <typename T> class vector {
vector() { ... }
vector(size_t n) { ... }
vector(size_t n, const T& t) { ... }
const vector(size_t n, T*) { ... } // can this be done?
...
If that is not possible, how about a container derived off of std::vector called std::const_vector, which (a) could construct from a pointer to a c-array and a size, and (b) purposefully did not implement non-const methods (push_back, resize, etc.), so then even if the object with a typename of const_vector is not actually a const object, the interface which only offers const methods makes it practically const (and any erroneous attempts to modify would be caught at compile time)?
UPDATE: A little messing around shows that this "solves" my problem wrt Windows-implementation of std::vector:
template <typename T>
class vector_tweaker : public std::vector<T> {
public:
vector_tweaker(size_t n, T* t) {
_saveMyfirst = _Myfirst;
_saveMylast = _Mylast;
_saveMyend = _Myend;
_Myfirst = t;
_Mylast = t + n;
_Myend = t + n;
}
~vector_tweaker() {
_Myfirst = _saveMyfirst;
_Mylast = _saveMylast;
_Myend = _saveMyend; // and proceed to std::vector destructor
}
private:
T* _saveMyfirst;
T* _saveMylast;
T* _saveMyend;
};
But of course that "solution" is hideous because (a) it offers no protection against the base class deleting the original memory by doing a resize() or push_back() (except for a careful user that only constructs const vector_tweaker()) -- and (b) it is specific to a particular implementation of std::vector, and would have to be reimplemented for others -- if indeed other platforms only declare their std::vector member data as protected: as microsoft did (seems a Bad Idea).
You can try reference-logic storing introduced in C++11 with std::reference_wrapper<>:
SomeClass cary[100];
// ...
std::vector<std::reference_wrapper<SomeClass>> cv;
cv.push_back(cary[i]); // no object copying is done, reference wrapper is stored
Or without C11, you can create a specialization of such template class for bytes - char. Then for the constructor from char* C-array you can use ::memcpy: which unfortunately will then use twice as much memory.
::memcpy(&v[0], c_arr, n);
Something like this:
template <typename T> class MyVector : public std::vector<T> {
};
template <> class MyVector<char> : public std::vector<char> {
public:
MyVector<char>(char* carr, size_t n) : std::vector<char>(n) {
::memcpy(&operator[](0), carr, n);
}
};
What I would recommend - replace all C-arrays to vectors where possible, then no extra copying will be needed.
How do I define a typedef for a fixed length array so that I can also 'new'. The following does not work:
typedef double Vector[3];
Vector *v = new Vector; // does not compile
We are trying to wrap into C++ some old C code which handles float * and float (*)[3] in a generic way.
The pointer to an double[3] is double * - so this will work:
typedef double Vector[3];
double *v = new Vector;
But I suggest you don't use it that way - to delete the array you need the array-delete-operator:
delete[] v;
But on new Vector you don't see it is an array and so it might be forgotten.
This case is handled (and strongly recommended to avoid) in Scott Meyers Effective C++. So better don't use an typedef here.
class Vector
{
public: // methods
double * data() { return mData; }
const double * data() const { return mData; }
double & operator[](int i) { return mData[i]; }
double operator[](int i) const { return mData[i]; }
private: // attributes
double mData[3];
};
will allow
Vector * pv = new Vector;
Vector & v = *pv;
v[0] = 1;
v[1] = 2;
v[2] = 3;
pass_it_to_legacy_lib(v.data());
delete pv;
One issue with your original example is that it would invoke the new operator where the new[] would actually be correct. Also, it would make it non-obvious that delete[] had to be used instead of plain delete.
The class approach doesn't need new[] and takes full advantage of the apriori fixed length.
If you're happy to use templates in your C++ code, something like this could work..
template <typename T, int S>
struct array
{
array() : _inst() {}
template<typename _F>
void operator()(_F & f)
{
f(_inst);
}
operator T*() { return _inst; }
// real array
T _inst[S];
};
typedef array<double, 4> d4;
void foo(double*)
{
}
int main(void)
{
d4 d; // no need for new, but you can use if you want
// first way to call is to pass the function to the array object, which will then
// visit
d(foo);
// take advantage of the type operator (operator T*)
foo(d);
}
#include <cassert>
#include <vector>
using namespace std;
template<typename Type, int Dimension>
const vector<Type> make_fixed_vector(const Type& value = Type())
{
return vector<Type>(Dimension, value);
}
int main(void)
{
vector<int> v3 = make_fixed_vector<int, 3>();
assert(v3.size() == 3);
}
C++1x compilers are able to deduce the type of a variable, which is handy when declaring multi-dimensional "fixed" vectors using this technique:
.
.
.
template<typename Type, int Rows, int Columns>
const vector<vector<Type> > make_fixed_vector_vector(const Type& value = Type())
{
return vector<vector<Type> >(Rows, make_fixed_vector<Type, Columns>(value));
}
int main(void)
{
auto vv = make_fixed_vector_vector<int, 3, 4>(42);
assert(vv.size() == 3);
assert(vv[0].size() == 4);
assert(vv[0][0] == 42);
assert(vv[2][3] == 42);
}
I had this simple idea when programming a parser-function for list expressions which shall return a fixed-size vector of vector of integers. For example, a vector<vector<int> >(1) for a expression like "(0,8)", but a vector<vector<int> >(2) for a expression like "(3-4)(5)" and so on. In the application up to 5 parenthesized definitions are possible, which represent logical references to program data. I first try to parse a vector<vector<int> >(5). Worked? Ok, got reference type A, the most detailed one. Otherwise vector<vector<int> >(4) indicates a reference type B etc.
For this purpose make_fixed_vector worked well, but from a general perspective the technique has flaws. Most notably, since make_fixed_vector returns no true type, its dimension(s) cannot be checked at compile-time. At runtime reserve, resize and push_back calls are possible. And, since function templates cannot have default template arguments, custom allocators require more typing:
template<typename Type, int Dimension, template<typename> class Allocator>
const vector<Type Allocator<Type> > make_fixed_vector(const Type& value = Type())
{
return vector<Type, Allocator<Type> >(Dimension, value);
}
vector<int> v3 = make_fixed_vector<int, 3, std::allocator>();
etc. etc. But this technique keeps smaller projects basic. Unless this virtue is relevant Boost's boost::array might be more realistic.