So I have this library code, see...
class Thing
{
public:
class Obj
{
public:
static const int len = 16;
explicit Obj(char *str)
{
strncpy(str_, str, len);
}
virtual void operator()() = 0;
private:
char str_[len];
};
explicit Thing(vector<Obj*> &objs) : objs_(objs) {}
~Thing() {
for(vector<Obj*>::iterator i = objs_.begin(); i != objs_.end(); ++i) {
delete *i;
}
}
private:
vector<Obj*> objs_;
}
And in my client code...
class FooObj : public Thing::Obj
{
virtual void operator()() {
//do stuff
}
}
class BarObj : public Thing::Obj
{
virtual void operator()() {
//do different stuff
}
}
vector<Objs*> objs;
int nStructs = system_call(*structs);
for(int i = 0; i < nStructs; i++) {
objs.push_back(newFooObj(structs[i].str));
}
objs.push_back(newBarObj("bar1");
objs.push_back(newBarObj("bar2");
Thing thing(objs);
// thing does stuff, including call Obj::()() on the elements of the objs_ vector
The thing I'm stuck on is exception safety. As it stands, if any of the Obj constructors throw, or the Thing constructor throws, the Objs already in the vector will leak. The vector needs to contain pointers to Objs because they're being used polymorphically. And, I need to handle any exceptions here, because this is being invoked from an older codebase that is exception-unaware.
As I see it, my options are:
Wrap the client code in a giant try block, and clean up the vector in the catch block.
Put try blocks around all of the allocations, the catch blocks of which call a common cleanup function.
Some clever RAII-based idea that I haven't thought of yet.
Punt. Realistically, if the constructors throw, the application is about to go down in flames anyway, but I'd like to handle this more gracefully.
Take a look at boost::ptr_vector
Since your Thing destructor already knows how to clean up the vector, you're most of the way towards a RAII solution. Instead of creating the vector of Objs, and then passing it to Thing's constructor, you could initialize Thing with an empty vector and add a member function to add new Objs, by pointer, to the vector.
This way, if an Obj's constructor throws, the compiler will automatically invoke Thing's destructor, properly destroying any Objs that were already allocated.
Thing's constructor becomes a no-op:
explicit Thing() {}
Add a push_back member:
void push_back(Obj *new_obj) { objs_.push_back(new_obj); }
Then the allocation code in your client becomes:
Thing thing(objs);
int nStructs = system_call(*structs);
for(int i = 0; i < nStructs; i++) {
thing.push_back(newFooObj(structs[i].str));
}
thing.push_back(newBarObj("bar1");
thing.push_back(newBarObj("bar2");
As another poster suggested, a smart pointer type inside your vector would also work well. Just don't use STL's auto_ptr; it doesn't follow normal copy semantics and is therefore unsuitable for use in STL containers. The shared_ptr provided by Boost and the forthcoming C++0x would be fine.
Answer 3 - Use smart pointers instead of Obj* in your vectors. I'd suggest boost::shared_ptr.
Vector of Obj can be very poor for performance, since a vector could have to move object on resize and has to copy them all. Pointers to objects are better.
I've used Pointainers which will do what you need. Here is the original code.
/*
* pointainer - auto-cleaning container of pointers
*
* Example usage:
* {
* pointainer< std::vector<int*> > v;
* // v can be manipulated like any std::vector<int*>.
*
* v.push_back(new int(42));
* v.push_back(new int(17));
* // v now owns the allocated int-s
*
* v.erase(v.begin());
* // frees the memory allocated for the int 42, and then removes the
* // first element of v.
* }
* // v's destructor is called, and it frees the memory allocated for
* // the int 17.
*
* Notes:
* 1. Assumes all elements are unique (you don't have two elements
* pointing to the same object, otherwise you might delete it twice).
* 2. Not usable with pair associative containers (map and multimap).
* 3. For ANSI-challenged compilers, you may want to #define
* NO_MEMBER_TEMPLATES.
*
* Written 10-Jan-1999 by Yonat Sharon <yonat##ootips.org>
* Last updated 07-Feb-1999
*
* Modified June 9, 2003 by Steve Fossen
* -- to fix g++ compiling problem with base class typenames
*/
#ifndef POINTAINER_H
#define POINTAINER_H
#ifdef NO_MEMBER_TEMPLATES
#include <functional> // for binder2nd
#endif
template <typename Cnt>
class pointainer : public Cnt
{
public:
// sf - change to fix g++ compiletime errors
#ifdef USE_USING_NOT_TYPEDEF
// I get compile errors with this
using typename Cnt::size_type;
using typename Cnt::difference_type;
using typename Cnt::reference;
using typename Cnt::const_reference;
using typename Cnt::value_type;
using typename Cnt::iterator;
using typename Cnt::const_iterator;
using typename Cnt::reverse_iterator;
using typename Cnt::const_reverse_iterator;
#else
// this way works
typedef typename Cnt::size_type size_type;
typedef typename Cnt::difference_type difference_type;
typedef typename Cnt::reference reference;
typedef typename Cnt::const_reference const_reference;
typedef typename Cnt::value_type value_type;
typedef typename Cnt::iterator iterator;
typedef typename Cnt::const_iterator const_iterator;
typedef typename Cnt::reverse_iterator reverse_iterator;
typedef typename Cnt::const_reverse_iterator const_reverse_iterator;
#endif
typedef pointainer< Cnt > its_type;
pointainer() {}
pointainer( const Cnt &c ) : Cnt( c ) {}
its_type &operator=( const Cnt &c ) { Cnt::operator=( c ); return *this; }
~pointainer() { clean_all(); }
void clear() { clean_all(); Cnt::clear(); }
iterator erase( iterator i ) { clean( i ); return Cnt::erase( i ); }
iterator erase( iterator f, iterator l ) { clean( f, l ); return Cnt::erase( f, l ); }
// for associative containers: erase() a value
size_type erase( const value_type& v )
{
iterator i = find( v );
size_type found( i != end() ); // can't have more than 1
if( found )
erase( i );
return found;
}
// for sequence containers: pop_front(), pop_back(), resize() and assign()
void pop_front() { clean( begin() ); Cnt::pop_front(); }
void pop_back() { iterator i( end() ); clean( --i ); Cnt::pop_back(); }
void resize( size_type s, value_type c = value_type() )
{
if( s < size() )
clean( begin() + s, end() );
Cnt::resize( s, c );
}
#ifndef NO_MEMBER_TEMPLATES
template <class InIter> void assign(InIter f, InIter l)
#else
void assign( iterator f, iterator l )
#endif
{
clean_all();
Cnt::assign( f, l );
}
#ifndef NO_MEMBER_TEMPLATES
template <class Size, class T> void assign( Size n, const T& t = T() )
#else
void assign( size_t n, const value_type& t = value_type() )
#endif
{
clean_all();
Cnt::assign( n, t );
}
// for std::list: remove() and remove_if()
void remove( const value_type& v )
{
clean( std::find( begin(), end(), v ));
Cnt::remove( v );
}
#ifndef NO_MEMBER_TEMPLATES
template <class Pred>
#else
typedef std::binder2nd< std::not_equal_to< value_type > > Pred;
#endif
void remove_if(Pred pr)
{
for( iterator i = begin(); i != end(); ++i )
if( pr( *i ))
clean( i );
Cnt::remove_if( pr );
}
private:
void clean( iterator i ) { delete *i; *i = 0; } // sf add *i = NULL so double deletes don't fail
void clean( iterator f, iterator l ) { while( f != l ) clean( f++ ); }
void clean_all() { clean( begin(), end() ); }
// we can't have two pointainers own the same objects:
pointainer( const its_type& ) {}
its_type& operator=( const its_type& ) { return NULL;} // sf - return null to remove no return value warning..
};
#endif // POINTAINER_H
Instead of a vector of pointers to Obj you always can use a vector of Obj. In that case you need to make sure you can copy Obj safely (dangerous when it contains pointers). As your Obj contains only a fixed size char array it should be safe, though.
Without changing the type stored in objs to a type that can be copied and manage Obj* itself, you need to add a try/catch block to cleanup objs if an exception is thrown. The easiest way would be to do this:
vector<Obj *> objs;
try {...}
catch (...)
{
// delete all objs here
throw;
}
Although you'll want to clean up objs anyway if an exception isn't thrown also.
Hmmm. I really like Commodore Jaeger's idea; it neatly clears up some of the funny smells this code was giving me. I'm reluctant to bring in the Boost libraries at this point; this is a somewhat conservative codebase, and I'd rather bring it into the 21st century squirming and complaining than kicking and screaming.
Related
Short version
Can I reinterpret_cast a std::vector<void*>* to a std::vector<double*>*?
What about with other STL containers?
Long version
I have a function to recast a vector of void pointers to a datatype specified by a template argument:
template <typename T>
std::vector<T*> recastPtrs(std::vector<void*> const& x) {
std::vector<T*> y(x.size());
std::transform(x.begin(), x.end(), y.begin(),
[](void *a) { return static_cast<T*>(a); } );
return y;
}
But I was thinking that copying the vector contents isn't really necessary, since we're really just reinterpreting what's being pointed to.
After some tinkering, I came up with this:
template <typename T>
std::vector<T*> recastPtrs(std::vector<void*>&& x) {
auto xPtr = reinterpret_cast<std::vector<T*>*>(&x);
return std::vector<T*>(std::move(*xPtr));
}
So my questions are:
Is it safe to reinterpret_cast an entire vector like this?
What if it was a different kind of container (like a std::list or std::map)? To be clear, I mean casting a std::list<void*> to std::list<T*>, not casting between STL container types.
I'm still trying to wrap my head around move semantics. Am I doing it right?
And one follow-up question: What would be the best way to generate a const version without code duplication? i.e. to define
std::vector<T const*> recastPtrs(std::vector<void const*> const&);
std::vector<T const*> recastPtrs(std::vector<void const*>&&);
MWE
#include <vector>
#include <algorithm>
#include <iostream>
template <typename T>
std::vector<T*> recastPtrs(std::vector<void*> const& x) {
std::vector<T*> y(x.size());
std::transform(x.begin(), x.end(), y.begin(),
[](void *a) { return static_cast<T*>(a); } );
return y;
}
template <typename T>
std::vector<T*> recastPtrs(std::vector<void*>&& x) {
auto xPtr = reinterpret_cast<std::vector<T*>*>(&x);
return std::vector<T*>(std::move(*xPtr));
}
template <typename T>
void printVectorAddr(std::vector<T> const& vec) {
std::cout<<" vector object at "<<&vec<<", data()="<<vec.data()<<std::endl;
}
int main(void) {
std::cout<<"Original void pointers"<<std::endl;
std::vector<void*> voidPtrs(100);
printVectorAddr(voidPtrs);
std::cout<<"Elementwise static_cast"<<std::endl;
auto dblPtrs = recastPtrs<double>(voidPtrs);
printVectorAddr(dblPtrs);
std::cout<<"reintepret_cast entire vector, then move ctor"<<std::endl;
auto dblPtrs2 = recastPtrs<double>(std::move(voidPtrs));
printVectorAddr(dblPtrs2);
}
Example output:
Original void pointers
vector object at 0x7ffe230b1cb0, data()=0x21de030
Elementwise static_cast
vector object at 0x7ffe230b1cd0, data()=0x21de360
reintepret_cast entire vector, then move ctor
vector object at 0x7ffe230b1cf0, data()=0x21de030
Note that the reinterpret_cast version reuses the underlying data structure.
Previously-asked questions that didn't seem relevant
These are the questions that come up when I tried to search this:
reinterpret_cast vector of class A to vector of class B
reinterpret_cast vector of derived class to vector of base class
reinterpret_cast-ing vector of one type to a vector of another type which is of the same type
And the answer to these was a unanimous NO, with reference to the strict aliasing rule. But I figure that doesn't apply to my case, since the vector being recast is an rvalue, so there's no opportunity for aliasing.
Why I'm trying to do this
I'm interfacing with a MATLAB library that gives me data pointers as void* along with a variable indicating the datatype. I have one function that validates the inputs and collects these pointers into a vector:
void parseInputs(int argc, mxArray* inputs[], std::vector<void*> &dataPtrs, mxClassID &numericType);
I can't templatize this part since the type is not known until runtime. On the other side, I have numeric routines to operate on vectors of a known datatype:
template <typename T>
void processData(std::vector<T*> const& dataPtrs);
So I'm just trying to connect one to the other:
void processData(std::vector<void*>&& voidPtrs, mxClassID numericType) {
switch (numericType) {
case mxDOUBLE_CLASS:
processData(recastPtrs<double>(std::move(voidPtrs)));
break;
case mxSINGLE_CLASS:
processData(recastPtrs<float>(std::move(voidPtrs)));
break;
default:
assert(0 && "Unsupported datatype");
break;
}
}
Given the comment that you're receiving the void * from a C library (something like malloc), it seems like we can probably narrow the problem down quite a bit.
In particular, I'd guess you're really dealing with something that's more like an array_view than a vector. That is, you want something that lets you access some data cleanly. You might change individual items in that collection, but you'll never change the collection as a whole (e.g., you won't try to do a push_back that could need to expand the memory allocation).
For such a case, you can pretty easily create a wrapper of your own that gives you vector-like access to the data--defines an iterator type, has a begin() and end() (and if you want, the others like rbegin()/rend(), cbegin()/cend() and crbegin()/crend()), as well as an at() that does range-checked indexing, and so on.
So a fairly minimal version could look something like this:
#pragma once
#include <cstddef>
#include <stdexcept>
#include <cstdlib>
#include <iterator>
template <class T> // note: no allocator, since we don't do allocation
class array_view {
T *data;
std::size_t size_;
public:
array_view(void *data, std::size_t size_) : data(reinterpret_cast<T *>(data)), size_(size_) {}
T &operator[](std::size_t index) { return data[index]; }
T &at(std::size_t index) {
if (index > size_) throw std::out_of_range("Index out of range");
return data[index];
}
std::size_t size() const { return size_; }
typedef T *iterator;
typedef T const &const_iterator;
typedef T value_type;
typedef T &reference;
iterator begin() { return data; }
iterator end() { return data + size_; }
const_iterator cbegin() { return data; }
const_iterator cend() { return data + size_; }
class reverse_iterator {
T *it;
public:
reverse_iterator(T *it) : it(it) {}
using iterator_category = std::random_access_iterator_tag;
using difference_type = std::ptrdiff_t;
using value_type = T;
using pointer = T *;
using reference = T &;
reverse_iterator &operator++() {
--it;
return *this;
}
reverse_iterator &operator--() {
++it;
return *this;
}
reverse_iterator operator+(size_t size) const {
return reverse_iterator(it - size);
}
reverse_iterator operator-(size_t size) const {
return reverse_iterator(it + size);
}
difference_type operator-(reverse_iterator const &r) const {
return it - r.it;
}
bool operator==(reverse_iterator const &r) const { return it == r.it; }
bool operator!=(reverse_iterator const &r) const { return it != r.it; }
bool operator<(reverse_iterator const &r) const { return std::less<T*>(r.it, it); }
bool operator>(reverse_iterator const &r) const { return std::less<T*>(it, r.it); }
T &operator *() { return *(it-1); }
};
reverse_iterator rbegin() { return data + size_; }
reverse_iterator rend() { return data; }
};
I've tried to show enough that it should be fairly apparent how to add most of the missing functionality (e.g., crbegin()/crend()), but I haven't worked really hard at including everything here, since much of what's left is more repetitive and tedious than educational.
This is enough to use the array_view in most of the typical vector-like ways. For example:
#include "array_view"
#include <iostream>
#include <iterator>
int main() {
void *raw = malloc(16 * sizeof(int));
array_view<int> data(raw, 16);
std::cout << "Range based:\n";
for (auto & i : data)
i = rand();
for (auto const &i : data)
std::cout << i << '\n';
std::cout << "\niterator-based, reverse:\n";
auto end = data.rend();
for (auto d = data.rbegin(); d != end; ++d)
std::cout << *d << '\n';
std::cout << "Forward, counted:\n";
for (int i=0; i<data.size(); i++) {
data[i] += 10;
std::cout << data[i] << '\n';
}
}
Note that this doesn't attempt to deal with copy/move construction at all, nor with destruction. At least as I've formulated it, the array_view is a non-owning view into some existing data. It's up to you (or at least something outside of the array_view) to destroy the data when appropriate. Since we're not destroying the data, we can use the compiler-generated copy and move constructors without any problem. We won't get a double-delete from doing a shallow copy of the pointer, because we don't do any delete when the array_view is destroyed.
No, you cannot do anything like this in Standard C++.
The strict aliasing rule says that to access an object of type T, you must use an expression of type T; with a very short list of exceptions to that.
Accessing a double * via a void * expression is not such an exception; let alone a vector of each. Nor is it an exception if you accessed the object of type T via an rvalue.
I have a big vector container that holds around 300.000 object. Also I have pointers to these objects.
Are there any fast way to get index of object in vector with using pointer?
Since vectors are organized sequentially, you can get an index by subtracting pointer to initial element from the pointer to element in question:
std::vector<MyObject> vect;
MyObject *ptrX = ... // Pointer to element in question
ptrdiff_t index = ptrX - &vect[0];
Iterator header should be useful in that case.
Let's assume you have something like:
using Vector = std::vector<Foo>;
using Iterator = Vector::iterator;
Vector big_vector;
And now your have an iterator to an object:
Iterator p_obj = get_Theobj(big_vector);
The the index could be easily get with distance:
auto index = std::distance(big_vector.begin(), p_obj);
// Note: index's type is a `difference_type` aka ptrdiff_t (usually signed integer).
The powerful of using that approach is the versatility. Indeed, it works with "C-like vector", std::array, std::list, as well.
You may use std::distance
std::vector<Object> objects = /*..*/;
const Object *p = /* object[i] */;
std::ptrdiff_t index = std::distance(objects.data(), p);
// Now index == i.
Plenty of good answers here. Combining them together, here's a little library suite which allows computation of the index of an item by either pointer or reference.
As an added bonus, the caller may optionally supply a policy object, to be enacted if the element is not in the container.
#include <stdexcept>
#include <cassert>
#include <vector>
struct exception_policy
{
[[noreturn]]
std::size_t out_of_range() const
{
throw std::out_of_range("index_of_element");
}
};
struct assertion_policy
{
std::size_t out_of_range() const
{
assert(!"out of range");
return _fallback.out_of_range();
}
exception_policy _fallback {};
};
struct zero_policy
{
std::size_t out_of_range() const
{
return 0;
}
};
template<class T, class A, class Policy = exception_policy>
std::size_t index_of_element(std::vector<T, A> const& vec,
typename std::vector<T, A>::const_pointer pitem,
Policy policy = Policy{})
{
auto pbegin = vec.data();
auto pend = pbegin + vec.size();
if (pitem < pbegin or pitem >= pend)
{
return policy.out_of_range();
}
else
{
return std::distance(pbegin, pitem);
}
}
template<class T, class A, class Policy = exception_policy>
std::size_t index_of_element(std::vector<T, A> const& vec,
typename std::vector<T, A>::const_reference item, Policy policy = Policy{})
{
return index_of_element(vec, std::addressof(item), policy);
}
int main()
{
std::vector<int> v = { 1, 2, 3, 4, 5, 6, 7, 8 };
auto px = std::addressof(v[5]);
auto& rx = *px;
try {
// use default policy of throwing out_of_range...
auto i = index_of_element(v, rx);
assert(i == 5);
}
catch(...)
{
assert(!"should not throw");
}
try {
auto i = index_of_element(v, px);
assert(i == 5);
}
catch(...)
{
assert(!"should not throw");
}
auto py = v.data() + 1000; // out of bounds
try {
auto i = index_of_element(v, py);
assert(!"should have thrown");
}
catch(std::out_of_range const& e)
{
// success
}
catch(...)
{
assert(!"should not throw this");
}
// specify a custom policy
auto i = index_of_element(v, ry, zero_policy());
assert(i == 0);
}
int getIndex(Object* pObject) {return pObject - &(my_vewctor[0]);}
Assuming C++11 at least:
You have some class Myclass; (hopefully a rather small one, since you have many instances of it).
You have some variable std::vector<Myclass> bigvec; and it is big enough so could have about half a million objects.
You have some valid pointer Myclass* ptr; and it could point inside an object from bigvec.
You might get its index in bigvec in int ix; (or better yet size_t ix;) using
if (ptr >= bigvec.data() && ptr < bigvec.data() + bigvec.size())
ix = ptr - bigvec.data();
However, be aware that you could have made copies of Myclass (e.g. thru assignment, passing by value some argument, etc...), and then a pointer to such a copy won't be in bigvec
Background
I'm working with an embedded platform with the following restrictions:
No heap
No Boost libraries
C++11 is supported
I've dealt with the following problem a few times in the past:
Create an array of class type T, where T has no default constructor
The project only recently added C++11 support, and up until now I've been using ad-hoc solutions every time I had to deal with this. Now that C++11 is available, I thought I'd try to make a more general solution.
Solution Attempt
I copied an example of std::aligned_storage to come up with the framework for my array type. The result looks like this:
#include <type_traits>
template<class T, size_t N>
class Array {
// Provide aligned storage for N objects of type T
typename std::aligned_storage<sizeof(T), alignof(T)>::type data[N];
public:
// Build N objects of type T in the aligned storage using default CTORs
Array()
{
for(auto index = 0; index < N; ++index)
new(data + index) T();
}
const T& operator[](size_t pos) const
{
return *reinterpret_cast<const T*>(data + pos);
}
// Other methods consistent with std::array API go here
};
This is a basic type - Array<T,N> only compiles if T is default-constructible. I'm not very familiar with template parameter packing, but looking at some examples led me to the following:
template<typename ...Args>
Array(Args&&... args)
{
for(auto index = 0; index < N; ++index)
new(data + index) T(args...);
}
This was definitely a step in the right direction. Array<T,N> now compiles if passed arguments matching a constructor of T.
My only remaining problem is constructing an Array<T,N> where different elements in the array have different constructor arguments. I figured I could split this into two cases:
1 - User Specifies Arguments
Here's my stab at the CTOR:
template<typename U>
Array(std::initializer_list<U> initializers)
{
// Need to handle mismatch in size between arg and array
size_t index = 0;
for(auto arg : initializers) {
new(data + index) T(arg);
index++;
}
}
This seems to work fine, aside from needing to handle a dimension mismatch between the array and initializer list, but there are a number of ways to deal with that that aren't important. Here's an example:
struct Foo {
explicit Foo(int i) {}
};
void bar() {
// foos[0] == Foo(0)
// foos[1] == Foo(1)
// ..etc
Array<Foo,10> foos {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
}
2 - Arguments Follow Pattern
In my previous example, foos is initialized with an incrementing list, similar to std::iota. Ideally I'd like to support something like the following, where range(int) returns SOMETHING that can initialize the array.
// One of these should initialize foos with parameters returned by range(10)
Array<Foo,10> foosA = range(10);
Array<Foo,10> foosB {range(10)};
Array<Foo,10> foosC = {range(10)};
Array<Foo,10> foosD(range(10));
Googling has shown me that std::initializer_list isn't a "normal" container, so I don't think there's any way for me to make range(int) return a std::initializer_list depending on the function parameter.
Again, there are a few options here:
Parameters specified at run-time (function return?)
Parameters specified at compile-time (constexpr function return? templates?)
Questions
Are there any issues with this solution so far?
Does anyone have a suggestion to generate constructor parameters? I can't think of a solution at runtime or compile-time other than hard-coding an std::initializer_list, so any ideas are welcome.
If i understand your problem correctly, I've also stumbled across std::array's total inflexibility regarding element construction in favor of aggregate initialization (and an absense of statically-allocated container with flexible element contruction options). The best approach I came up with was creating a custom array-like container which accepts an iterator to construct it's elements.
This is totally flexible solution:
Works for both fixed-size and dynamic-sized containers
Can pass different or same parameters to element constructors
Can call constructors with one or multiple (tuple piecewise construction) arguments, or even different constructors for different elements (with inversion of control)
For your example it would be like:
const size_t SIZE = 10;
std::array<int, SIZE> params;
for (size_t c = 0; c < SIZE; c++) {
params[c] = c;
}
Array<Foo, SIZE> foos(iterator_construct, ¶ms[0]); //iterator_construct is a special tag to call specific constructor
// also, we are able to pass a pointer as iterator, since it has both increment and dereference operators
Note: you can totally skip parameters array allocation here by using custom iterator class, which calculates it's value from it's position on-the-fly.
For multiple-argument constructor that would be:
const size_t SIZE = 10;
std::array<std::tuple<int, float>, SIZE> params; // will call Foo(int, float)
for (size_t c = 0; c < SIZE; c++) {
params[c] = std::make_tuple(c, 1.0f);
}
Array<Foo, SIZE> foos(iterator_construct, piecewise_construct, ¶ms[0]);
Concrete implementation example is kinda big piece of code, so please let me know if you want more insights into implementation details besides the general idea - I will update my answer then.
I'd use a factory lambda.
The lambda takes a pointer to where to construct and an index, and is responsible for constructing.
This makes copy/move easy to write as well, which is a good sign.
template<class T, std::size_t N>
struct my_array {
T* data() { return (T*)&buffer; }
T const* data() const { return (T const*)&buffer; }
// basic random-access container operations:
T* begin() { return data(); }
T const* begin() const { return data(); }
T* end() { return data()+N; }
T const* end() const { return data()+N; }
T& operator[](std::size_t i){ return *(begin()+i); }
T const& operator[](std::size_t i)const{ return *(begin()+i); }
// useful utility:
bool empty() const { return N!=0; }
T& front() { return *begin(); }
T const& front() const { return *begin(); }
T& back() { return *(end()-1); }
T const& back() const { return *(end()-1); }
std::size_t size() const { return N; }
// construct from function object:
template<class Factory,
typename std::enable_if<!std::is_same<std::decay_t<Factory>, my_array>::value, int> =0
>
my_array( Factory&& factory ) {
std::size_t i = 0;
try {
for(; i < N; ++i) {
factory( (void*)(data()+i), i );
}
} catch(...) {
// throw during construction. Unroll creation, and rethrow:
for(std::size_t j = 0; j < i; ++j) {
(data()+i-j-1)->~T();
}
throw;
}
}
// other constructors, in terms of above naturally:
my_array():
my_array( [](void* ptr, std::size_t) {
new(ptr) T();
} )
{}
my_array(my_array&& o):
my_array( [&](void* ptr, std::size_t i) {
new(ptr) T( std::move(o[i]) );
} )
{}
my_array(my_array const& o):
my_array( [&](void* ptr, std::size_t i) {
new(ptr) T( o[i] );
} )
{}
my_array& operator=(my_array&& o) {
for (std::size_t i = 0; i < N; ++i)
(*this)[i] = std::move(o[i]);
return *this;
}
my_array& operator=(my_array const& o) {
for (std::size_t i = 0; i < N; ++i)
(*this)[i] = o[i];
return *this;
}
private:
using storage = typename std::aligned_storage< sizeof(T)*N, alignof(T) >::type;
storage buffer;
};
it defines my_array(), but that is only compiled if you try to compile it.
Supporting initializer list is relatively easy. Deciding what to do when the il isn't long enough, or too long, is hard. I think you might want:
template<class Fail>
my_array( std::initializer_list<T> il, Fail&& fail ):
my_array( [&](void* ptr, std::size_t i) {
if (i < il.size()) new(ptr) T(il[i]);
else fail(ptr, i);
} )
{}
which requires you pass in a "what to do on fail". We could default to throw by adding:
template<class WhatToThrow>
struct throw_when_called {
template<class...Args>
void operator()(Args&&...)const {
throw WhatToThrow{"when called"};
}
};
struct list_too_short:std::length_error {
list_too_short():std::length_error("list too short") {}
};
template<class Fail=ThrowWhenCalled<list_too_short>>
my_array( std::initializer_list<T> il, Fail&& fail={} ):
my_array( [&](void* ptr, std::size_t i) {
if (i < il.size()) new(ptr) T(il[i]);
else fail(ptr, i);
} )
{}
which if I wrote it right, makes a too-short initializer list cause a meaningful throw message. On your platform, you could just exit(-1) if you don't have exceptions.
This is very similar to auto_ptr for arrays. However, my wrinkle is I don't want an initialized array, which is what a vector would provide (the const T& value = T()):
explicit vector(size_type count,
const T& value = T(),
const Allocator& alloc = Allocator());
I don't want the array initialized because its a large array and the values will be immediately discarded.
I'm currently hacking it with the following, but it feels like something is wrong with it:
//! deletes an array on the heap.
template <class T>
class AutoCleanup
{
public:
AutoCleanup(T*& ptr) : m_ptr(ptr) { }
~AutoCleanup() { if (m_ptr) { delete[] m_ptr; m_ptr = NULL; }}
private:
T*& m_ptr;
};
And:
// AutoCleanup due to Enterprise Analysis finding on the stack based array.
byte* plaintext = new byte[20480];
AutoCleanup<byte> cleanup(plaintext);
// Do something that could throw...
What does C++ provide for an array of a POD type that is uninitialized and properly deleted?
The project is C++03, and it has no external dependencies, like Boost.
From your question, it's not easy to interpret what you actually need. But I guess you want an array which is stack-guarded (i.e. lifetime bound to the stack), heap-allocated, uninitialized, dynamically or statically sized, and compatible with pre-C++11 compilers.
auto_ptr can't handle arrays (because it doesn't call delete[] in its destructor, but rather delete).
Instead, I would use boost::scoped_array together with new[] (which doesn't initialize POD types afaik).
boost::scoped_array<MyPodType> a(new MyPodType[20480]);
If you don't want to use boost, you can reimplement scoped_array pretty easily by pasting the code together which this class includes from the boost library:
#include <cassert>
#include <cstddef>
// From <boost/checked_delete.hpp>:
template<class T>
inline void checked_array_delete(T * x)
{
typedef char type_must_be_complete[sizeof(T) ? 1 : -1];
(void) sizeof(type_must_be_complete);
delete [] x;
}
// From <boost/smartptr/scoped_array.hpp>:
template<class T>
class scoped_array
{
private:
T * px;
// Make this smart pointer non-copyable
scoped_array(scoped_array const &);
scoped_array & operator=(scoped_array const &);
typedef scoped_array<T> this_type;
public:
typedef T element_type;
explicit scoped_array(T * p = 0) : px(p) { }
~scoped_array() {
checked_array_delete(px);
}
void reset(T * p = 0) {
assert(p == 0 || p != px); // catch self-reset errors
this_type(p).swap(*this);
}
T & operator[](std::ptrdiff_t i) const {
assert(px != 0);
assert(i >= 0);
return px[i];
}
T * get() const {
return px;
}
operator bool () const {
return px != 0;
}
bool operator ! () const {
return px == 0;
}
void swap(scoped_array & b) {
T * tmp = b.px;
b.px = px;
px = tmp;
}
};
I have a vector< Object > myvec which I use in my code to hold a list of objects in memory. I keep a pointer to the current object in that vector in the "normal" C fashion by using
Object* pObj = &myvec[index];
This all works fine if... myvec doesn't grow big enough that it is moved around during a push_back at which time pObj becomes invalid - vectors guarantee data is sequential, hence they make no effort to keep the vector at the same memory location.
I can reserve enough space for myvec to prevent this, but I dnt' like that solution.
I could keep the index of the selected myvec position and when I need to use it just access it directly, but it's a costly modification to my code.
I'm wondering if iterators keep the their references intact as a vector is reallocated/moved and if so can I just replace
Object* pObj = &myvec[index];
by something like
vector<Object>::iterator = myvec.begin()+index;
What are the implication of this?
Is this doable?
What is the standard pattern to save pointers to vector positions?
Cheers
No... using an iterator you would have the same exact problem. If a vector reallocation is performed then all iterators are invalidated and using them is Undefined Behavior.
The only solution that is reallocation-resistant with an std::vector is using the integer index.
Using for example std::list things are different, but also the are different efficiency compromises, so it really depends on what you need to do.
Another option would be to create your own "smart index" class, that stores a reference to the vector and the index. This way you could keep just passing around one "pointer" (and you could implement pointer semantic for it) but the code wouldn't suffer from reallocation risks.
Iterators are (potentially) invalidated by anything that could resize the vector (e.g., push_back).
You could, however, create your own iterator class that stored the vector and an index, which would be stable across operations that resized the vector:
#include <iterator>
#include <algorithm>
#include <iostream>
#include <vector>
namespace stable {
template <class T, class Dist=ptrdiff_t, class Ptr = T*, class Ref = T&>
class iterator : public std::iterator<std::random_access_iterator_tag, T, Dist, Ptr, Ref>
{
T &container_;
size_t index_;
public:
iterator(T &container, size_t index) : container_(container), index_(index) {}
iterator operator++() { ++index_; return *this; }
iterator operator++(int) { iterator temp(*this); ++index_; return temp; }
iterator operator--() { --index_; return *this; }
iterator operator--(int) { stable_itertor temp(*this); --index_; return temp; }
iterator operator+(Dist offset) { return iterator(container_, index_ + offset); }
iterator operator-(Dist offset) { return iterator(container_, index_ - offset); }
bool operator!=(iterator const &other) const { return index_ != other.index_; }
bool operator==(iterator const &other) const { return index_ == other.index_; }
bool operator<(iterator const &other) const { return index_ < other.index_; }
bool operator>(iterator const &other) const { return index_ > other.index_; }
typename T::value_type &operator *() { return container_[index_]; }
typename T::value_type &operator[](size_t index) { return container_[index_ + index]; }
};
template <class T>
iterator<T> begin(T &container) { return iterator<T>(container, 0); }
template <class T>
iterator<T> end(T &container) { return iterator<T>(container, container.size()); }
}
#ifdef TEST
int main() {
std::vector<int> data;
// add some data to the container:
for (int i=0; i<10; i++)
data.push_back(i);
// get iterators to the beginning/end:
stable::iterator<std::vector<int> > b = stable::begin(data);
stable::iterator<std::vector<int> > e = stable::end(data);
// add enough more data that the container will (probably) be resized:
for (int i=10; i<10000; i++)
data.push_back(i);
// Use the previously-obtained iterators:
std::copy(b, e, std::ostream_iterator<int>(std::cout, "\n"));
// These iterators also support most pointer-like operations:
std::cout << *(b+125) << "\n";
std::cout << b[150] << "\n";
return 0;
}
#endif
Since we can't embed this as a nested class inside of the container like a normal iterator class, this requires a slightly different syntax to declare/define an object of this type; instead of the usual std::vector<int>::iterator whatever;, we have to use stable::iterator<std::vector<int> > whatever;. Likewise, to obtain the beginning of a container, we use stable::begin(container).
There is one point that may be a bit surprising (at least at first): when you obtain a stable::end(container), that gets you the end of the container at that time. As shown in the test code above, if you later add more items to the container, the iterator your obtained previously is not adjusted to reflect the new end of the container -- it retains the position it had when you obtained it (i.e., the position that was the end of the container at that time, but isn't any more).
No, iterators are invalidated after vector growth.
The way to get around this problem is to keep the index to the item, not a pointer or iterator to it. This is because the item stays at its index, even if the vector grows, assuming of course that you don't insert any items before it (thus changing its index).