while writing a offset array class(your idxs go from lets say 100 to 1000, so you create class that takes that into account without wasting first 100 slots in the array) I ran into a problem.
How to initialize a class that has an C array of elements(problem is that T doesnt have def constructor). Basically I want the array to be totally uninitiated. Example:
class MyClass
{
MyClass(int i)
{
}
};
template <typename T, size_t n, size_t offset>
struct offsetedIdxArray
{
T data[n];// error line : error C2512: 'MyClass' : no appropriate default constructor available
offsetedIdxArray()
{
}
T& operator [](size_t pos)
{
return data[(pos-offset)];
}
};
usage:
offsetedIdxArray<MyClass, 1024,offset> oia;
Making def constructor is not the option because class I use is in fact library class.
*EDIT: * not related to problem described here, but it turned out that my precious library class doesnt have copy ctor, just move ctor, so I had to use vector of unique_ptr.
To get a statically-sized uninitialized portion of storage, you can use an "untyped" buffer of aligned storage, like std::aligned_storage<sizeof(T[n]), alignof(T)>::type in C++11 (in C++03 you need to use a char[sizeof(T[n])+something] and do manual corrections for alignment, or use a char[sizeof(T[n])] and compiler extensions to specify alignment).
That means using placement new for constructors, and explicit destructor calls for destruction. It is up to you to track what parts of that storage have objects (and thus needs destruction) and what parts don't have objects (and can't have destructors called on). It is also up to you to cater for when the client requests an element that isn't initialized at all (there's no object at the place it's supposed to be).
An alternative is to use an array of boost::optionals, and then you don't have to care about destruction and can simply assign new elements to their respective index.
Related
My teammates are writing a fixed-size implementation of std::vector for a safety-critical application. We're not allowed to use heap allocation, so they created a simple array wrapper like this:
template <typename T, size_t NUM_ITEMS>
class Vector
{
public:
void push_back(const T& val);
...more vector methods
private:
// Internal storage
T storage_[NUM_ITEMS];
...implementation
};
A problem we encountered with this implementation is that it requires elements present default constructors (which is not a requirement of std::vector and created porting difficulties). I decided to hack on their implementation to make it behave more like std::vector and came up with this:
template <typename T, size_t NUM_ITEMS>
class Vector
{
public:
void push_back(const T& val);
...more vector methods
private:
// Internal storage
typedef T StorageType[NUM_ITEMS];
alignas(T) char storage_[NUM_ITEMS * sizeof(T)];
// Get correctly typed array reference
StorageType& get_storage() { return reinterpret_cast<T(&)[NUM_ITEMS]>(storage_); }
const StorageType& get_storage() const { return reinterpret_cast<const T(&)[NUM_ITEMS]>(storage_); }
};
I was then able to just search and replace storage_ with get_storage() and everything worked. An example implementation of push_back might then look like:
template <typename T, size_t NUM_ITEMS>
void Vector<T, NUM_ITEMS>::push_back(const T& val)
{
get_storage()[size_++] = val;
}
In fact, it worked so easily that it got me thinking.. Is this a good/safe use of reinterpret_cast? Is the code directly above a suitable alternative to placement new, or are there risks associated with copy/move assignment to an uninitialized object?
EDIT: In response to a comment by NathanOliver, I should add that we cannot use the STL, because we cannot compile it for our target environment, nor can we certify it.
The code you've shown is only safe for POD types (Plain Old Data), where the object's representation is trivial and thus assignment to an unconstructed object is ok.
If you want this to work in all generality (which i assume you do due to using a template), then for a type T it is undefined behavior to use the object prior to construction it. That is, you must construct the object before your e.g. assignment to that location. That means you need to call the constructor explicitly on demand. The following code block demonstrates an example of this:
template <typename T, size_t NUM_ITEMS>
void Vector<T, NUM_ITEMS>::push_back(const T& val)
{
// potentially an overflow test here
// explicitly call copy constructor to create the new object in the buffer
new (reinterpret_cast<T*>(storage_) + size_) T(val);
// in case that throws, only inc the size after that succeeds
++size_;
}
The above example demonstrates placement new, which takes the form new (void*) T(args...). It calls the constructor but does not actually perform an allocation. The visual difference is the inclusion of the void* argument to operator new itself, which is the address of the object to act on and call the constructor for.
And of course when you remove an element you'll need to destroy that explicitly as well. To do this for a type T, simply call the pseudo-method ~T() on the object. Under templated context the compiler will work out what this means, either an actual destructor call, or no-op for e.g. int or double. This is demonstrated below:
template<typename T, size_t NUM_ITEMS>
void Vector<T, NUM_ITEMS>::pop_back()
{
if (size_ > 0) // safety test, you might rather this throw, idk
{
// explicitly destroy the last item and dec count
// canonically, destructors should never throw (very bad)
reinterpret_cast<T*>(storage_)[--size_].~T();
}
}
Also, I would avoid returning a refernce to an array in your get_storage() method, as it has length information and would seem to imply that all elements are valid (constructed) objects, which of course they're not. I suggest you provide methods for getting a pointer to the start of the contiguous array of constructed objects, and another method for getting the number of constructed objects. These are the .data() and .size() methods of e.g. std::vector<T>, which would make use of your class less jarring to seasoned C++ users.
Is this a good/safe use of reinterpret_cast?
Is the code directly above a suitable alternative to placement new
No. No.
or are there risks associated with copy/move assignment to an uninitialized object?
Yes. The behaviour is undefined.
Assuming memory is uninitialised, copying the vector has undefined behaviour.
No object of type T has started its lifetime at the memory location. This is super bad when T is not trivial.
The reinterpretation violates the strict aliasing rules.
First is fixed by value-initialising the storage. Or by making the vector non-copyable and non-movable.
Second is fixed by using placement new.
Third is technically fixed by using using the pointer returned by placement new, but you can avoid storing that pointer by std::laundering after reinterpreting the storage.
I believe this is a common problem, but some googling does not return match, hence ask here.
So I have the following class:
class A {
public:
A(const A &rhs) { m_a = rhs.m_a; }
private:
int m_a;
};
Everything is cool until some time later, could be a year later, I add a new property, m_b to class A, but I forget to update the copy constructor.
It takes a painful debug to locate the out-of-sync.
Is there a trick to avoid such a problem, ideally at build time?
Yes, I can write unit test to cover that copy constructor, but when I forget updating copy constructor, most likely I forget that unit test also.
Turn on all your compiler warnings. You should hopefully get a warning about any uninitialized member variables. On GCC the specific flag for this is -Weffc++. See this StackOverflow post for more info.
Also, assign your values in the initializer list and not the constructor body whenever possible.
The best approach is probably to rely on the default copy constructor. For instance, your particular example, which involves a member-wise copy, works fine with the default constructor (i.e., the behavior would be the same even if you simply deleted the constructor). As more members are added, they will automatically receive the same member-wise copy behavior in the default constructor.
In some unusual cases you might want to force the generation of the default constructor (e.g., when you want to have some different, explicitly defined behavior for non-const source objects). In that case, in C++11 and later, you can explicitly request the default copy constructor as follows:
A(const A&) = default;
Some coding guidelines also recommend always including the above explicit request for the default constructor simply as a form of documentation.
Mostly member-wise, with exceptions
Sometimes, most member of a class are fine with the default member-wise copy, but you have a couple of exceptions. An example would be a raw pointer where you want to perform a deep copy of the underlying data. By default, the pointer is simply copied and so the pointers in the source object and new object will both point to the same location in memory.
The solution is fairly simple: just wrap this pointer and any associated meta-data (e.g., a length field if the pointed to object is an array) in a suitable RAII wrapper whose copy constructor performs the specific non-default behavior you want, and include a member of this type in your class A. Now A can continue to use the default copy constructor, which calls your explicit copy constructor for your pointer. Essentially, you are back to the pure member-wise copy, but with the new semantics for your pointer-wrapping member.
This type of matter will also help you keep your destructor and sometimes your constructors trivial as well. No doubt the original class above had some code to delete your raw pointer. Once wrapped with the copying-RAII wrapper, the wrapper takes care of destruction and so the containing class doesn't have to, and often the destructor can be removed entirely.
This wrapper approach often has zero or close to zero overhead in a language like C++.
You can find some more details in this question.
When that doesn't work
Sometimes the above may not work. One example would be when the copy constructor needs to embed the address (the this pointer) of the new object in some field. The self-contained wrapper doesn't have a way to get the this pointer of the containing object (indeed, it doesn't even know it is a member).
One approach here is to create a new sub-object with all of the fields of your original object that use the default copy behavior, and then create your new top level object by aggregating (or by inheritance) this sub-object with the few fields that do need special treatment. Then you can keep the using the default copy constructor for all the fields that should have the default treatment.
This approach can even have performance benefits, since compilers are likely to use a pure memcpy approach1 for the sub-object, in addition to calling your explicit code for the exceptional fields. When the fields were mingled together in the original object, this is much less likely or impossible (e.g., because the layout of the object may interleave the exceptional fields and default-copied fields).
1 This doesn't actually mean that there will be a call to the standard library memcpy in the code: for small objects the compiler will usually unroll this for small objects into an unrolled sequence of mostly maximum width loads and stores.
The only time you ever need to write copy constructors, assignment operators or destructors is if your class is an RAII wrapper for exactly one resource.
If your class is managing more than one resource, it's time to refactor it so that it's composed of classes which manage exactly one resource.
example:
#include <algorithm>
// this class is managing two resources.
// This will be a maintenance nightmare and will required
// horribly complicated constructor code.
struct DoubleVector
{
int *vec1;
int *vec2;
};
// this class manages a single resource
struct SingleVector
{
SingleVector() : vec (new int[10]) {}
SingleVector(SingleVector const& other)
: vec (new int[10])
{
// note - simple constructor
std::copy(other.vec, other.vec + 10, vec);
}
SingleVector& operator=(SingleVector const& other)
{
auto temp = other;
std::swap(vec, temp.vec);
return *this;
}
~SingleVector() {
delete [] vec;
}
// note - single resource
int *vec;
};
// this class uses *composition* and default assignment/construction/destruction
// it will never go wrong. And it could not be simpler.
struct DoubleVectorDoneRight
{
SingleVector vec1;
SingleVector vec2;
};
int main()
{
SingleVector v;
SingleVector v2 = v;
SingleVector v3;
v3 = v;
}
Okay, so I have a large vector say
vector<vector<vector<int>>>
of 10000 by 10000 by 10000.
I have a class which has such a vector as a private member variable:
class foo {
private:
vector<vector<vector<int>>> myvector
};
I have a constructor for my class that uses pass by reference and initializer list:
foo(vector<vector<vector<int>>> &myvector_in) : myvector(myvector_in);
I want to know what's exactly happening in terms of memory usage. Is the private myvector the same as the one that was originally declared, or is it a copy.
Basically, I want to know if there are ever two version of myvector in memory.
Thank You!
Here is a fishing tip.
Fairly easy to answer yourself. Set [0][0][0] of myvector_in to a known value. Invoke the constructor and inside it also set [0][0][0] but of myvector to a different value. Once the constructor has returned, print the content of myvector_in. If it's the same as the one you original set you must conclude that the two vectors are different entities, thus one was copied into a different one. If they are the same than you can conclude they are in fact the same instances.
You could also print addresses to get a better sense of what's what.
I must point out, the memory requirement mention in your original question are in the realm of super computer, you got one?
You have a member of type vector<vector<vector<int>>> and initialize it with another vector<vector<vector<int>>>. How would it be possible not to have said data twice in memory? Thats more a matter of logic than a matter of c++.
Alternatives
You could store a pointer vector<vector<vector<int>>>* or a reference vector<vector<vector<int>>>& to the vector in an appropriate class member. Or use one of the smart pointers to do so. In any of these cases some serious thinking about memory management is a good idea.
Or you use a move constructor, which is moving the passed in vector in your member vector.
using vec = std::vector<std::vector<std::vector<int>>>;
class foo {
public:
foo() = delete;
foo(const vec&) = delete;
foo(vec&& myvector_in) : myvector(std::move(myvector_in)) {};
private:
vec myvector;
};
Of course that will render that argument passed to the constructor useless but that a trivial consequence of the not-copying you want.
You can pass your vector to that constructor if you first cast it to an rvalue using std::move:
foo my_foo(std::move(test));
The easy way of addressing this issue in C++11 (and newer) is to accept the constructor argument by value:
struct foo {
using vec=std::vector<std::vector<std::vector<int>>>; // from DrSvanHay
foo(vec v) : myvector(std::move(v)) {}
private:
vec myvector;
};
Surprisingly, this actually minimizes copies:
If the client has a vector cv;, cv gets copied into the parameter v, but that copy was necessary to have cv and foo::myvector upon completion.
If the client passes std::move(cv), cv gets moved into v and there is no copy.
If the client passes make_vector(...), the parameter v is move-initialized from the return value (or, in C++17, is the return value).
(In all these cases, v is then moved into foo::myvector, of course.)
I would like to know, if I have a class with an array attribute whose size is not the same for all instances :
class myObject{
private:
int size;
int* array;
// other methods/attributes
};
Is it obligatory allocated using new ?
explicit myObject(int size = 0):size(size){
array = new int[size];
}
Even if in the main(), I always use constant parameters to create the instances of the class ? (Meaning I know every array size at compile time).
int main{
myObject object (5);
return 0;
}
Apparently something like :
private:
int size;
int array[size];
wont work, no ?
That means that array attribute whose size are not constant of the class are obligatory on the heap ?
Thank you for your answers,
That class contains no array. What you called array is a pointer; you cannot store any ints in it. If you really do just store a pointer, you'll have to allocate the memory yourself somehow; it can't magically appear. You'll also have to deallocate it yourself, and make sure that copying and assigning myObject objects doesn't cause any issues.
However, it's unlikely that a pointer is really the best way to do things. The standard library provides the std::vector class template which lets you use almost exactly the syntax you want:
class myObject {
std::vector<int> vector;
public:
myObject() {};
explicit myObject(std::size_t n) : vector(n) {}
};
With this in place you can create myObjects and they'll have the right amount of storage ready for them. It'll likely be dynamically allocated using operator new[], just like if you'd do it manually, but you don't have to worry about copying or deleting it.
int main() {
myObject a; // default-constructed, vector is empty.
myObject b(10); // std::size_t constructor, vector has 10 elements.
} // scope exit, b and a destroyed.
You can use the vector member much like if it was an array; the only thing it does not support is implicit decay to pointer, but the data member function makes up for even that.
As an alternative, if you always know the size at compile-time you can change the class into a class template and make the size a template parameter:
template<std::size_t N>
class myObject{
std::array<int, N> array;
// other methods/attributes
};
However, note that you now cannot use myObject<10> to a function expecting myObject<20>.
It is unlikely that you want more control than the above possibilities provide -- std::vector can be given an allocator, so it can do almost all work for you -- you could use std::unique_ptr<int[]> and make_unique together to make things work for you. However, if you need this kind of power, you probably know it yourself.
As a closing note, if you're just learning C++ and your book doesn't cover std::vectors somewhere early on, perhaps it's best to get a different book; they're one of the most commonly-useful data structures in the standard library and definitely not something to be left in an appendix.
If you need a variable sized array as a member of a class, don't use built-in arrays directly. Instead, use std::vector<T>, e.g.:
class myObject {
std::vector<int> array;
public:
explicit myObject(int size = 0): array(size){}
};
You can get the std:vector<int>'s size using array.size(), i.e., there is no need to store the size separately. Also, the content is automatically default initialized.
I am trying to create a class which has a private member that is an array. I do not know the size of the array and will not until the value is passed into the constructor. What is the best way to go about defining the class constructor as well as the definition in the .h file to allow for this variable size of the array?
If you want a "real" C-style array, you have to add a pointer private member to your class, and allocate dynamically the memory for it in the constructor (with new). Obviously you must not forget to free it in the destructor.
class YourClass
{
private:
int * array;
size_t size;
// Private copy constructor operator to block copying of the object, see later
// C++03:
YourClass(const YourClass &); // no definition
// C++11:
YourClass(const YourClass&) = delete;
public:
YourClass(size_t Size) : array(new int[Size]), size(Size)
{
// do extra init stuff here
};
~YourClass()
{
delete [] array;
}
};
To make this work easier, you may consider to use a smart pointer (for example, a boost::scoped_array in C++03, or plain std::unique_ptr in C++11), that you may initialize using the initializer list before the constructor or simply in the constructor.
class YourClass
{
private:
boost::scoped_array<int> array; // or in C++11 std::unique_ptr<int[]> array;
size_t size;
public:
YourClass(size_t Size) : array(new int[Size]), size(Size)
{
// do extra init stuff here
}
// No need for a destructor, the scoped_array does the magic
};
Both these solutions produce noncopyable objects (you didn't specify if they had to be copyable and their copy semantic); if the class don't have to be copied (which happens most of times), these both are ok, and the compiler will generate an error if you try to copy/assign one class to another, in the first case because the default copy constructor has been overloaded with a private one (or plain deleted in C++11), in the second case because boost::scoped_array and std::unique_ptr are noncopyable.
If, instead, you want to have copyable objects, then you must decide if you want to create a copy that shares the array (so, just a pointer copy) or if you want to create a new, separate array for the other object.
In the first case, you must be very careful before freeing the allocated memory, since other objects may be using it; a reference-counter is the most common solution. You can be helped in this by boost::shared_array (or std::shared_ptr in C++11), which does all the tracking work automatically for you.
If instead you want to do a "deep copy", you'll have to allocate the new memory and copy all the objects of the source array to the target array. This is not completely trivial to do correctly, and is usually accomplished through the "copy and swap idiom".
Still, the simplest solution is to use a std::vector as a private member: it would handle all the allocation/deallocation stuff by itself, constructing/destroying itself correctly when the object of your class is constructed/destructed. Moreover, it implements the deep-copy semantic out of the box. If you need to make your callers access the vector read-only, then, you could write a getter that returns a const_iterator or a const reference to the vector object.
Using a std::vector is the best option.
If you ever need to pass it to a function that expects a pointer to an array (like the GSL often does), you can still pass &vec[0]...