Suppose I have a MyStack class which exposes:
class MyStack {
public:
template <typename T>
T* Push() {
Reserve(sizeof(T)); // Make sure that the buffer can hold an additional sizeof(T) bytes , realloc if needed
auto prev= _top;
_top += sizeof(T);
new (prev) T();
return reinterpret_cast<T*>(prev);
}
template <typename T>
T* Pop() {
_top -= sizeof(T);
return return reinterpret_cast<T*>(_top);
}
bool Empty() const {
return _bottom == _top;
}
private:
char* _bottom;
char* _top;
};
// Assumes all stack elements have the same type
template <typename T>
void ClearStack(MyStack& stack) {
while (!stack.Empty()) {
stack.template Pop<T>()->~T();
}
}
There's a hidden bug here. Constructing T in MyStack::Push() could throw which would leave the stack buffer in an undefined state (the allocated space would contain garbage). Later, when ClearStack is called, it will attempt to reinterpret the garbage as T and invoke its destructor which could cause an access violation.
Is there a way to fix this bug by only modifying MyStack::Push()? (the limitation is because this is an external code and we prefer to make minimal changes so it's relatively easy to update the library)
I thought about changing MyStack::Push to:
T* Push() {
auto prev = _top;
T t();
Reserve(sizeof(T));
_top += sizeof(T);
reinterpret_cast<T*>(prev) = std::move(t);
return prev;
}
But it looks bad and I'm not even sure that it doesn't invoke any UB (and also forces T to have a move constructor)
Is there a better solution here to protect against throwing constructors? (preferably a small change inside MyStack::Push())
The problem here is really that your design is wrong. You're making a type that behaves a bit like std::vector, but it has no actual concept of "capacity". So when it Reserves memory, it genuinely expects that _top will point to the end of the allocated storage after this process has completed. And therefore if it doesn't, the type is in an invalid state.
Which means that, in the event of an exception, you have to undo the call to Reserve: reallocating the old size of storage and moving the stuff in that storage back1. A more vector-like implementation has 3 pointers: a pointer to the start, a pointer to the first unused byte of memory, and a pointer to past the end of the allocated storage. This way, if you Reserve but get an exception, you've simply got some extra storage lying around.
1: FYI: what you seem to be trying to do most likely will not work. Or at least, not with most user-defined C++ types. Odds are good that your Reserve call allocates new storage and does a memcpy into it and never calls the destructor on those objects (since you have no idea what type they are). Well, that's only legal for objects for which memcpy is a valid action. Namely, TriviallyCopyable types. Yet your Push function has nothing to guard it against non-TriviallyCopyable types.
Not to mention the fact that if anyone had a pointer to the old object, every Push call will invalidate that pointer. And since you don't remember the types of any objects, there's no way to reconstitute them.
How about this code:
template <typename T>
T* Push() {
Reserve(sizeof(T));
auto prev= _top;
_top += sizeof(T);
try {
new (prev) T();
return reinterpret_cast<T*>(prev);
}
catch (...) {
Unreserve(sizeof(T)); //release the memory, optional?
_top = prev;
throw;
}
}
You could use three-pointer implementation:
begin points to the first element.
end points to one past the last element
reserved points to one element past the reserved space.
begin=end=reserved(=nullptr) represents non-allocated container.
begin+1=end=reserved represents filled container with one element.
begin+1=end;begin+4=reserved represents container with one element and space for 2 more.
Then your Push method would look like:
template <typename T>
T* Push() {
if(end==reserved)
//relocate, ensure that begin<=end<reserved
new (end) T();
end+=sizeof(T);
return reinterpret_cast<T*>(end-1);
}
Related
So as the title says, I'm wondering what the proper way to move an element in an array such as:
std::array<std::aligned_storage_t<sizeof(T), alignof(T)>, N> data;
Is it as simple as doing:
data[dst] = data[src];
Or do I need to add something else like a move, being that its storage is uninitialized, do I need to use the copy or move constructors, something like:
new (&data[dst]) T(std::move(data[src]));
Since the data[src] is not the proper type T, do i need to instead do:
new (&data[dst]) T(std::move(*std::launder(reinterpret_cast<T*>(&data[src])));
I'm looking for the most flexible way of moving the item for anything T might be, including move only types etc.
Basically I'm creating a packed array that always moves elements to be contiguous in memory, even when ones are removed to prevent holes in the active section of the array.
Edit:
As the comments want a minimal example, I guess something like:
template<class T, std::size_t N>
class SimpleExampleClass {
std::array<std::aligned_storage_t<sizeof(T), alignof(T)>, N> data;
public:
void move_element(std::size_t src, std::size_t dst) {
// data[dst] = data[src]; ?
// or
// new (&data[dst]) T(std::move(data[src]));
// or
// new (&data[dst]) T(std::move(*std::launder(reinterpret_cast<T*>(&data[src])));
// or
// something else?
// then I would need some way to clean up the src element, not sure what would suffice for that.
// as calling a destructor on it could break something that was moved potentially?
}
// Other functions to manipulate the data here... (example below)
template<typename ...Args>
void emplace_push(Args&&... args) noexcept {
new (&data[/*some index*/]) T(std::forward<Args>(args)...);
}
void push(T item) noexcept {
emplace_push(std::move(item));
}
};
std::aligned_storage itself is, roughly speaking, just a collection of bytes. There is nothing to move, and std::move(data[src]) is just a no-op. You should first use placement new to create an object and then you can move that object by move-constructing it at the new location.
Simple example:
auto ptr = new (&data[0]) T();
new (&data[1]) T(std::move(*ptr));
std::destroy_at(ptr);
in the case of T being something like unique_ptr, or any other similar edge case, there shouldn't be any issue with calling the destroy on the old element index correct?
Moving from an object leaves it in some valid state, and the object still has to be destroyed.
since data[0] is just a collection of bytes, would a pointer to it work, or would that pointer need to be reinterpret cast before being used in the move constructor?
It will work if it is adorned with reinterpret_cast and std::launder, like you wrote in your question:
new (&data[1]) T(std::move(*std::launder(reinterpret_cast<T*>(&data[0]))));
The Standard library contains some useful functions for working with uninitialized memory. The complete list can be found here (see the Uninitialized storage section).
There are some questions quite similar around here, but they couldn't help me get my mind around it.
Also, I'm giving a full example code, so it might be easier for others to understand.
I have made a vector container (couldn't use stl for memory reasons) that used to use only operator= for push_back*, and once I came accross placement new, I decided to introduce an additional "emplace_back" to it**.
*(T::operator= is expected to deal with memory management)
**(the name is taken from a similar function in std::vector that I've encountered later, the original name I gave it was a mess).
I read some stuff about the danger of using placement new over operator new[] but couldn't figure out if the following is ok or not, and if not, what's wrong with it, and what should I replace it with, so I'd appreciate your help.
This is of couse a simplified code, with no iterators, and no extended functionality, but it makes the point :
template <class T>
class myVector {
public :
myVector(int capacity_) {
_capacity = capacity_;
_data = new T[_capacity];
_size = 0;
}
~myVector() {
delete[] _data;
}
bool push_back(T const & t) {
if (_size >= _capacity) { return false; }
_data[_size++] = t;
return true;
}
template <class... Args>
bool emplace_back(Args const & ... args) {
if (_size >= _capacity) { return false; }
_data[_size].~T();
new (&_data[_size++]) T(args...);
return true;
}
T * erase (T * p) {
//assert(/*p is not aligned*/);
if (p < begin() || p >= end()) { return end(); }
if (p == &back()) { --_size; return end(); }
*p = back();
--_size;
return p;
}
// The usual stuff (and more)
int capacity() { return _capacity; }
int size() { return _size; }
T * begin() { return _data; }
T * end() { return _data + _size; }
T const * begin() const { return _data; }
T const * end() const { return _data + _size; }
T & front() { return *begin(); }
T & back() { return *(end() - 1); }
T const & front() const { return *begin(); }
T const & back() const { return *(end() - 1); }
T & operator[] (int i) { return _data[i]; }
T const & operator[] (int i) const { return _data[i]; }
private:
T * _data;
int _capacity;
int _size;
};
Thanks
I read some stuff about the danger of using placement new over
operator new[] but couldn't figure out if the following is ok or not,
and if not, what's wrong with it [...]
For operator new[] vs. placement new, it's only really bad (as in typically-crashy type of undefined behavior) if you mix the two strategies together.
The main choice you typically have to make is to use one or the other. If you use operator new[], then you construct all the elements for the entire capacity of the container in advance and overwrite them in methods like push_back. You don't destroy them on removal in methods like erase, just kind of keep them there and adjust the size, overwrite elements, and so forth. You both construct and allocate a multiple elements all in one go with operator new[], and destroy and deallocate them all in one go using operator delete[].
Why Placement New is Used For Standard Containers
First thing to understand if you want to start rolling your own vectors or other standard-compliant sequences (that aren't simply linked structures with one element per node) in a way that actually destroys elements when they are removed, constructs elements (not merely overwrite them) when added, is to separate the idea of allocating the memory for the container and constructing the elements for it in place. So quite to the contrary, in this case, placement new isn't bad. It's a fundamental necessity to achieve the general qualities of the standard containers. But we can't mix it with operator new[] and operator delete[] in this context.
For example, you might allocate the memory to hold 100 instances of T in reserve, but you don't want to default construct them as well. You want to construct them in methods like push_back, insert, resize, the fill ctor, range ctor, copy ctor, etc. -- methods that actually add elements and not merely the capacity to hold them. That's why we need placement new.
Otherwise we lose the generality of std::vector which avoids constructing elements that aren't there, can copy construct in push_backs rather than simply overwriting existing ones with operator=, etc.
So let's start with the constructor:
_data = new T[_capacity];
... this will invoke the default constructors for all the elements. We don't want that (neither the default ctor requirement nor this expense), as the whole point of using placement new is to construct elements in-place of allocated memory, and this would have already constructed all elements. Otherwise any use of placement new anywhere will try to construct an already-constructed element a second time, and will be UB.
Instead you want something like this:
_data = static_cast<T*>(malloc(_capacity * sizeof(T)));
This just gives us a raw chunk of bytes.
Second, for push_back, you're doing:
_data[_size++] = t;
That's trying to use the assignment operator, and, after our previous modification, on an uninitialized/invalid element which hasn't been constructed yet. So we want:
new(_data + _size) T(t);
++size;
... that makes it use the copy constructor. It makes it match up with what push_back is actually supposed to do: creating new elements in the sequence instead of simply overwriting existing ones.
Your erase method needs some work even at the basic logic level if you want to handle removals from the middle of the container. But just from the resource management standpoint, if you use placement new, you want to manually invoke destructors for removed elements. For example:
if (p == &back()) { --_size; return end(); }
... should be more like:
if (p == &back())
{
--size;
(_data + _size)->~T();
return end();
}
Your emplace_back manually invokes a destructor but it shouldn't do this. emplace_back should only add, not remove (and destroy) existing elements. It should be quite similar to push_back but simply invoking the move ctor.
Your destructor does this:
~myVector() {
delete[] _data;
}
But again, that's UB when we take this approach. We want something more like:
~myVector() {
for (int j=0; j < _size; ++j)
(_data + j)->~T();
free(_data);
}
There's still a whole lot more to cover like exception-safety which is a whole different can of worms.
But this should get you started with respect to proper usage of placement new in a data structure against some memory allocator (malloc/free in this exemplary case).
Last but not least:
(couldn't use stl for memory reasons)
... this might be an unusual reason. Your implementation doesn't necessarily use any less memory than a vector with reserve called in advance to give it the appropriate capacity. You might shave off a few bytes for on a per-container-level (not on a per-element level) with the choice of 32-bit integrals and no need to store an allocator, but it's going to be a very small memory savings in exchange for a boatload of work.
This kind of thing can be a useful learning exercise though to help you build some data structures outside the standard in a more standard-compliant way (ex: unrolled lists which I find quite useful).
I ended up having to reinvent some vectors and vector-like containers for ABI reasons (we wanted a container we could pass through our API that was guaranteed to have the same ABI regardless of what compiler was used to build a plugin). Even then, I would have much preferred simply using std::vector.
Note that if you just want to take control of how vector allocates memory, you can do that by specifying your own allocator with a compliant interface. This might be useful, for example, if you want a vector which allocates 128-bit aligned memory for use with aligned move instructions using SIMD.
Lets say I have a function to get data into an std vector:
void getData(std::vector<int> &toBeFilled) {
// Push data into "toBeFilled"
}
Now I want to send this data to another function, that should free the data when finished:
void useData(int* data)
{
// Do something with the data...
delete[] data;
}
Both functions (getData and useData) are fixed and cannot be changed. This works fine when copying the data once:
{
std::vector<int> data;
getData(data);
int *heapData = new int[data.size()];
memcpy(heapData, data.data(), data.size()*sizeof(int));
useData(heapData);
data.clear();
}
However, this memcpy operation is expensive and not really required, since the data is already on the heap. Is it possible to directly extract and use the data allocated by the std vector? Something like (pseudocode):
{
std::vector<int> data;
getData(data);
useData(data.data());
data.clearNoDelete();
}
Edit:
The example maybe doesn't make too much sense, since it is possible to just free the vector after the function call to useData. However, in the real code, useData is not a function but a class that receives the data, and this class lives longer than the vector...
No.
The API you're using has a contract that states it takes ownership of the data you provide it, and that this data is provided through a pointer. This basically rules out using standard vectors.
Vector will always assuredly free the memory it allocated and safely destroy the elements it contains. That is part of its guaranteed contract and you cannot turn that off.
You have to make a copy of the data if you wish to take ownership of them... or move each element out into your own container. Or start with your own new[] in the first place (ugh) though you can at least wrap all this in some class that mimics std::vector and becomes non-owning.
Here's a horrible hack which should allow you to do what you need, but it relies on Undefined Behaviour doing the simplest thing it can. The idea is to create your own allocator which is layout-compatible with std::allocator and type-pun the vector:
template <class T>
struct CheatingAllocator : std::allocator<T>
{
using typename std::allocator<T>::pointer;
using typename std::allocator<T>::size_type;
void deallocate(pointer p, size_type n) { /* no-op */ }
// Do not add ANY data members!!
};
{
std::vector<int, CheatingAllocator<int>> data;
getData(reinterpret_cast<std::vector<int>&>(data)); // type pun, `getData()` will use std::allocator internally
useData(data.data());
// data actually uses your own allocator, so it will not deallocate anything
}
Note that it's as hacky and unsafe as hacks go. It relies on the memory layout not changing and it relies of std::allocator using new[] inside its allocate function. I wouldn't use this in production code myself, but I believe it is a (desperate) solution.
#TonyD correctly pointed out in the comments that std::allocator is quite likely to not use new[] internally. Therefore, the above would most likely fail on the delete[] inside useData(). The same #TonyD also made a good point about using reserve() to (hopefully) prevent reallocation inside getData(). So the updated code would look like this:
template <class T>
struct CheatingAllocator : std::allocator<T>
{
using typename std::allocator<T>::pointer;
using typename std::allocator<T>::size_type;
pointer allocate(size_type n) { return new T[n]; }
void deallocate(pointer p, size_type n) { /* no-op */ }
// Do not add ANY data members!!
};
{
std::vector<int, CheatingAllocator<int>> data;
data.reserve(value_such_that_getData_will_not_need_to_reallocate);
getData(reinterpret_cast<std::vector<int>&>(data)); // type pun, `getData()` will use std::allocator internally
useData(data.data());
// data actually uses your own allocator, so it will not deallocate anything
}
for example, I try to write my own vector, so I just write its assign function like this
template <typename T>
void Vector<T> :: assign(T *start, T *end)
{
if (end - start > _capacity)
{
resize(end - start);
}
_size = end - start;
delete []ptr;
ptr = new T[_capacity];
memcpy(ptr, start, end - start);
}
I have new the pointer ptr before, but I can copy all I what between the pointer start and end
why? Thankyou very much.
First problem is that this only works for simple types (read POD).
Anything with a constructor/destructor needs to have them called.
Second this is not exception safe.
It does not even provide the basic guarantee let a lone the strong guarantee.
You need to do all exception unsafe work before modifying the object. This means the new must be done before you modify the object (and definitely before the free). Otherwise you could potentially throw leaving the object in an invalid state (that might not seem bad, but what if you catch the exception and continue you now have an object that contains a pointer to released memory).
So even if you use std::copy() you still have done the wrong thing.
Personally I think the suggestion of std::copy() is a red herring. It will copy the data correctly but you are still writing your method badly. You need to use a twist on the copy and swap idium.
template <typename T>
void Vector<T> :: assign(T *start, T *end)
{
Vector<T> tmp(start, end); // construct a temp object that allocates the memory.
swap(tmp); // Swap the current object and the tmp objects data.
// When the tmp object goes out of scope it will delete
// what was the current objects data
}
It is perfectly fine to reuse the pointer in this way, but it is not safe to use memcpy here because you don't know what type T is. If T is an object type like string or vector, this causes undefined behavior.
To fix this, change the line to
std::copy(start, end, ptr);
Which is the safe, C++ way of doing this.
Hope this helps!
Per-frame I need to allocate some data that needs to stick around until the end of the frame.
Currently, I'm allocating the data off a different memory pool that allows me to mark it with the frame count. At the end of the frame, I walk the memory pool and delete the memory that was allocated in a particular frame.
The problem I'm running into is that in order to keep a hold on the data, I have to place it in a structure thusly:
struct FrameMemory
{
uint32 frameIndex;
bool allocatedType; //0 = new(), 1 = new[]
void* pMemPtr;
}
So later, when i get around to freeing the memory, it looks something like this:
{
for(all blocks)
if(block[i].frameIndex == targetIndex)
if(block[i].allocatedType == 0)
delete block[i].pMemPtr;
else if (block[i].allocatedType ==1)
delete[] block[i].pMemPtr;
}
The issue is that, because I have to overload the pointer to the memory as a void*, the DELETE operator doesn't properly DELETE the memory as its' native base type. IE the destructor NEVER gets called for the object.
I've attempted to find ways to use smart-pointer templated objects for the solution, but in order to do that, I have to overload the templated class to a non-templated base-type, which makes deletion even more difficult.
Does anyone have a solution to a problem like this?
If you don't want to force all the objects to inherit from Destructible, you can store a pointer to a deleter function (or functor) along with the pointer to the data itself. The client code is responsible for providing a function that knows how to delete the data correctly, typically something like:
void xxx_deleter(void *data) {
xxx *ptr = static_cast<xxx *>(data);
delete ptr;
}
Though the deleter will usually be a lot like the above, this also gives the client the option of storing complex data structures and still getting them deleted correctly.
class Destructable
{
public:
virtual ~Destructable() {}
};
Instead of void *, store Destructable * in the pool. Make objects allocated from the pool inherit from Destructable.
Alternatively, override the operators new and delete for the relevant classes. Make them use the pool. Delete the object as soon as the CPU is done with it, in the regular way, in the code that owns it and hence knows its correct type; since the pool will not reuse the memory until it sees the appropriate frame end, whatever asynchronous hardware required you to lag garbage collection in this way can still do its thing.
The only way I could think of to do that would be to add a type entry to the FrameMemory struct, then use that to properly cast the memory for the delete. For example, if you have memory of type foo, you could have something like:
if (block[i].BlockType == BLOCKTYPE_FOO)
{
foo *theMemory = (foo *)block[i].pMemPtr;
delete theMemory;
}
Note that this can be an ****extremely**** dangerous operation if you do it wrong.
If you are mean stack frame (i.e. inside function)
you can try to use alloca()
First thing that I can think of is using boost::shared_ptr<void> (for the non-array version, some work may be required to adapt it for the array version) as the pointer type. And I think that should take care of mostly every detail. Whenever the frame is destroyed the memory will be appropriately deleted:
struct FrameMemory
{
uint32 frameIndex;
// bool allocatedType; //0 = new(), 1 = new[] only works with instances, not arrays
boost::shared_ptr<void> pMemPtr;
};
If you want to implement something similar manually, you can use a 'deleter' function pointer to handle the deletion of the objects, instead of calling delete directly. Here is a rough approach to how you could modify your code:
// helper deleter functions
template <typename T>
void object_deleter( void *p ) {
delete static_cast<T*>(p);
}
template <typename T>
void array_deleter( void *p ) {
delete [] static_cast<T*>(p);
}
class FrameMemory
{
public:
const uint32 frameIndex;
void* pMemPtr;
private:
void (*deleter)(void*);
public:
template <typename T>
FrameMemory( uint32 frame, T* memory, bool isarray = false )
: frameIndex(frame), pMemPtr(memory),
deleter( isarray? array_deleter<T> : object_deleter<T> )
{}
void delete() {
deleter(pMemPtr)
}
};
struct X;
void usage()
{
{
FrameMemory f( 1, new X );
f.delete();
}
{
FrameMemory f( 1, new x[10], true );
f.delete();
}
}
I would modify it further so that instead of having to call FrameMemory::delete() that was performed in the destructor, but that would take more time than I have right now to do correctly (that is, deciding how copies are to be handled and so on...
I would do something like this:
struct FrameMemoryBase
{
uint32 frameIndex;
bool allocatedType; //0 = new(), 1 = new[]
virtual void Free() = 0;
};
template <typename T>
struct FrameMemory : public FrameMemoryBase
{
void Free()
{
if(allocatedType == 0)
delete pMemPtr;
else if (allocatedType ==1)
delete[] pMemPtr;
}
T *pMemPtr;
};
which you would use via:
{
for(all blocks)
if(block[i].frameIndex == targetIndex)
block[i].Free();
}
If you also free the FrameMemory struct you could just change Free to a virtual destructor. I'm not sure this is what you're looking for since I don't understand what "I've attempted to find ways to use smart-pointer templated objects for the solution, but in order to do that, I have to overload the templated class to a non-templated base-type, which makes deletion even more difficult." means, but I hope this is helpful.
This requires that the memory management code somehow have access to the declarations of what you wish to free, but I don't think there's any way around that, assuming you want destructors called, which you explicitly do.