Access violation when reserve is called on a map - c++

I have a few unordered_maps that I use with custom allocators. In this case I use a rudimentary bump allocator that just simply linearly allocates new memory from an existing continiuos block.
But when I try and call reserve on these maps after a while, they throw an access violaton exception at the line within the std list file I'll show below in :
_List_unchecked_const_iterator& operator++() noexcept {
_Ptr = _Ptr->_Next;
return *this;
}
My allocator has enough memory left so I don't think it's because I am running out of memory.
Here's some self contained code that demonstrates it. Copy/paste and run it to see the issue.
#include <stdlib.h>
#include <unordered_map>
#include <vector>
#include <list>
#include <memory>
#define SEQ(type, val) sizeof(type) * val
struct ImpAllocator {
virtual void* Allocate(size_t pSize) = 0;
virtual void Free(void* pPtr) = 0;
};
struct SysAllocator : public ImpAllocator {
void* Allocate(size_t pSize) override {
return malloc(pSize);
}
void Free(void* pPtr) override {
free(pPtr);
}
};
template <class T>
class StdAllocatorWrapper {
public:
std::shared_ptr<ImpAllocator> mInternalAllocator;
using value_type = T;
StdAllocatorWrapper() = default;
StdAllocatorWrapper(std::shared_ptr<ImpAllocator> pInternalAllocator) :
mInternalAllocator(pInternalAllocator)
{}
~StdAllocatorWrapper() = default;
StdAllocatorWrapper(const StdAllocatorWrapper<T>& pOther) = default;
template<class U>
StdAllocatorWrapper(const StdAllocatorWrapper<U>& pOther) {
this->mInternalAllocator = pOther.mInternalAllocator;
}
value_type* allocate(size_t pNumberOfObjects) {
return reinterpret_cast<T*>(mInternalAllocator->Allocate(SEQ(T, pNumberOfObjects)));
}
void deallocate(value_type* pPointer, size_t pNumberOfObjects) {
mInternalAllocator->Free(pPointer);
}
};
template <class T, class U>
bool operator==(StdAllocatorWrapper<T> const& pL, StdAllocatorWrapper<U> const& pR) noexcept {
return pL.mInternalAllocator == pR.mInternalAllocator;
}
template <class T, class U>
bool operator!=(StdAllocatorWrapper<T> const& pL, StdAllocatorWrapper<U> const& pR) noexcept {
return !(pL == pR);
}
template<typename T> using AllocWrapper = StdAllocatorWrapper<T>;
template<typename T, typename K> using Pair = std::pair<const T, K>;
template<typename T, typename K> using PairAllocWrapper = StdAllocatorWrapper<Pair<T, K>>;
template<typename T> using AllocatedVector = std::vector<T, AllocWrapper<T>>;
template<typename T> using AllocatedList = std::list<T, AllocWrapper<T>>;
template<typename T, typename K> using AllocatedUnorderedMap = std::unordered_map<T, K, std::hash<T>, std::equal_to<T>, PairAllocWrapper<T, K>>;
typedef unsigned char* MemBlock;
class BumpAllocator : public ImpAllocator {
private:
std::shared_ptr<ImpAllocator> mInternalAllocator;
size_t mSize;
MemBlock mBlock;
MemBlock mStart;;
size_t mCurrent;
public:
BumpAllocator(size_t pSize, std::shared_ptr<ImpAllocator> pInternalAllocator) :
mInternalAllocator(pInternalAllocator),
mSize(pSize),
mCurrent(0) {
mBlock = reinterpret_cast<MemBlock>(mInternalAllocator->Allocate(pSize));
mStart = mBlock;
}
~BumpAllocator() {
mInternalAllocator->Free(mBlock);
}
void* Allocate(size_t pSize) override {
printf("\n bump allocator wrapper requested: %d", pSize);
if (mCurrent + pSize > mSize) {
return nullptr;
}
MemBlock _return = mBlock + mCurrent;
mCurrent += pSize;
return _return;
}
void Free(void* pFre) override {
}
void Reset() {
mCurrent = 0;
}
};
struct Animation {
};
struct Texture {
};
struct TextureArrayIndex {
//TexturePointer mTexture;
unsigned int mIndex;
std::shared_ptr<Texture> mTexture;
};
struct RenderOrder {
float mDeltaTime;
std::string mAnimationName;
std::shared_ptr<Animation> mAnim;
};
using Textures = AllocatedUnorderedMap<int, TextureArrayIndex>;
using TexturesAllocWrapper = PairAllocWrapper<int, TextureArrayIndex>;
using RenderOrdersVector = AllocatedVector<RenderOrder>;
using RenderOrdersAllocWrapper = AllocWrapper<RenderOrder>;
using RenderBucket = AllocatedUnorderedMap<unsigned int, RenderOrdersVector>;
using RenderBuckets = AllocatedUnorderedMap<std::shared_ptr<Animation>, RenderBucket>;
using RenderBucketAllocWrapper = PairAllocWrapper<unsigned int, RenderOrdersVector>;
using RenderBucketsAllocWrapper = PairAllocWrapper<std::shared_ptr<Animation>, RenderBucket>;
struct Renderer {
std::shared_ptr<BumpAllocator> mInternalAllocator;
Textures mTextureArrayIndexMap;
RenderBuckets mAnimationRenderBuckets;
Renderer(std::shared_ptr<ImpAllocator> pAllocator) :
mInternalAllocator(std::make_shared<BumpAllocator>(60000, pAllocator)),
mTextureArrayIndexMap(Textures(TexturesAllocWrapper(mInternalAllocator))),
mAnimationRenderBuckets(RenderBuckets(RenderBucketsAllocWrapper(mInternalAllocator)))
{}
void Begin() {
mTextureArrayIndexMap = Textures(TexturesAllocWrapper(mInternalAllocator));
mTextureArrayIndexMap.reserve(2);
mAnimationRenderBuckets = RenderBuckets(RenderBucketsAllocWrapper(mInternalAllocator));
mAnimationRenderBuckets.reserve(1000);
}
void Render() {
}
void Flush() {
mInternalAllocator->Reset();
}
};
int main(int argc, char* argv[]) {
Renderer _renderer(std::make_shared<SysAllocator>());
for (int i = 0; i < 1000; i++) {
_renderer.Begin();
_renderer.Flush();
}
}
What's weird is that , the first 2 iterations work fine. But the third one fails... So reusing the memory works for the first 2 Begin--->Flush cycles but then the 3d one fail every time. So odd.

I could not reproduce the error with the code given... But the code does not use std::unordered_map, so the error must come from there.
First issue. In your allocators:
void* SysAllocator::Allocate(size_t pSize) override {
return malloc(pSize); // allocator returns NULL on error.
}
void* BumpAllocator::Allocate(size_t pSize) override {
printf("\n bump allocator wrapper requested: %d", pSize);
if (mCurrent + pSize > mSize) {
return nullptr; // allocator returns NULL on error.
}
MemBlock _return = mBlock + mCurrent;
mCurrent += pSize;
return _return;
}
Your custom allocators return NULL on error, but STL containers expect their allocators to throw a std::bad_alloc exception on error. That's mandatory.
You should change your allocators:
void* SysAllocator::Allocate(size_t pSize) override {
void* p = malloc(pSize);
if (!p)
throw std::bad_alloc();
return p;
}
void* BumpAllocator::Allocate(size_t pSize) override {
printf("\n bump allocator wrapper requested: %d", pSize);
if (mCurrent + pSize > mSize)
throw std::bad_alloc();
MemBlock _return = mBlock + mCurrent;
mCurrent += pSize;
return _return;
}
This will not solve your problem, but the point of error will have moved to the time of allocation.
I think your problem comes from a lack of memory. std::unordered_map uses hash buckets, and these could very likely use more memory than you anticipated. To investigate, set breakpoints on the throw lines in your Allocate() functions to catch the error right when it happens.

Apart from the issue mentioned by Michael Roy, there is another bug here
void Reset() {
mCurrent = 0;
}
This method, which is called indirectly from your main, means that further allocations will reuse already allocated memory. This is the immediate cause of the crash in the code you posted.
If you comment out the line mCurrent = 0; then you do actually run out of memory and you get the null pointer bug explained by Michael Roy in the other answer.
Tested with MSVC (since that seems to be significant).

I figured it out finally. The problem was that inside the Begin method, I am initializing the maps again. This happens after Reset is called. Meaning the memory allocation takes place from the beginning. This would be fine. However, at this time. Both the new maps and the old ones exist at the same time and they overlap fully on the same memory. This also would be fine but then when the new map is assigned to the old one, the destructor of the old one is called and it frees the memory that is being used by the newly instantiated maps.
I fixed the issue by making the maps pointers ( std::unordered_map* ) . So now my map "reinstantiation" is as follows mTextureArrayIndexMap = new Textures(...) . So the destructor of the old map is not called. And this is perfectly fine since the whole thing is being allocated on a bump memory that is reset.
The code runs smoothly now with no issues!

Related

getting a segfault when I try to deep copy `unique_ptr`s

Why can't I return a unique_ptr from a clone function? I thought I could do this.
I have a base class for different mathematical functions called transform. I have a container of pointers to this type because I am using polymorphism. For example, all these derived classes have a different implementation of log_jacobian that is useful for statistical algorithms.
I am using unique_ptrs to this transform class, and so I have made a (pure virtual) clone function that makes new unique_ptr pointing to a deep copy of the same mathematical transform object. This new object is of the same type that derives from transform<float_t>, but it's a separate because you can't have two unique_ptrs pointing to the same thing.
template<typename float_t>
class transform{
...
virtual std::unique_ptr<transform<float_t>> clone() const = 0;
...
};
My transform_container class holds a few of these at a time. After all, most statistical models have more than one parameter.
template<typename float_t, size_t numelem>
class transform_container{
private:
using array_ptrs = std::array<std::unique_ptr<transform<float_t>>, numelem>;
array_ptrs m_ts;
unsigned m_add_idx;
...
auto get_transforms() const -> array_ptrs;
};
I'm not sure why the deep copy function get_transforms isn't working, though. It is used to make copies, and to access individual transformations from the container. I get a segfault when I run some tests. If I run it in gdb, it explicitly tells me the line with a comment after it is bad.
template<typename float_t, size_t numelem>
auto transform_container<float_t,numelem>::get_transforms() const -> array_ptrs
{
array_ptrs deep_cpy;
for(size_t i = 0; i < numelem; ++i){
deep_cpy[i] = m_ts[i]->clone(); // this line
}
return deep_cpy;
}
I've also tried std::moveing it into deep_cpy[i] and using unique_ptr::reset, but to no avail.
Edit:
here are some other relevant methods: a method that adds transforms to transform_container, and the factory method for the individual transform:
template<typename float_t>
std::unique_ptr<transform<float_t> > transform<float_t>::create(trans_type tt)
{
if(tt == trans_type::TT_null){
return std::unique_ptr<transform<float_t> >(new null_trans<float_t> );
}else if(tt == trans_type::TT_twice_fisher){
return std::unique_ptr<transform<float_t> >(new twice_fisher_trans<float_t> );
}else if(tt == trans_type::TT_logit){
return std::unique_ptr<transform<float_t> >(new logit_trans<float_t> );
}else if(tt == trans_type::TT_log){
return std::unique_ptr<transform<float_t> >(new log_trans<float_t> );
}else{
throw std::invalid_argument("that transform type was not accounted for");
}
}
template<typename float_t, size_t numelem>
void transform_container<float_t, numelem>::add_transform(trans_type tt)
{
m_ts[m_add_idx] = transform<float_t>::create(tt);
m_add_idx++;
}
In get_transforms(), you are looping over the entire m_ts[] array, calling clone() on all elements - even ones that have not been assigned by add_transform() yet! Unassigned unique_ptrs will be holding a nullptr pointer, and it is undefined behavior to call a non-static class method through a nullptr.
The easiest fix is to change the loop in get_transforms() to use m_add_idx instead of numelem:
template<typename float_t, size_t numelem>
auto transform_container<float_t,numelem>::get_transforms() const -> array_ptrs
{
array_ptrs deep_cpy;
for(size_t i = 0; i < m_add_idx; ++i){ // <-- here
deep_cpy[i] = m_ts[i]->clone();
}
return deep_cpy;
}
Otherwise, you would have to manually ignore any nullptr elements, eg:
template<typename float_t, size_t numelem>
auto transform_container<float_t,numelem>::get_transforms() const -> array_ptrs
{
array_ptrs deep_cpy;
for(size_t i = 0, j = 0; i < numelem; ++i){
if (m_ts[i]) {
deep_cpy[j++] = m_ts[i]->clone();
}
}
return deep_cpy;
}
Either way, you should update add_transform() to validate that m_add_idx will not exceed numelem:
template<typename float_t, size_t numelem>
void transform_container<float_t, numelem>::add_transform(trans_type tt)
{
if (m_add_idx >= numelem) throw std::length_error("cant add any more transforms"); // <-- here
m_ts[m_add_idx] = transform<float_t>::create(tt);
++m_add_idx;
}
That being said, since transform_container can have a variable number of transforms assigned to it, I would suggest changing transform_container to use a std::vector instead of a std::array, eg:
template<typename float_t>
class transform_container{
private:
using vector_ptrs = std::vector<std::unique_ptr<transform<float_t>>>;
vector_ptrs m_ts;
...
auto get_transforms() const -> vector_ptrs;
};
template<typename float_t>
auto transform_container<float_t>::get_transforms() const -> vector_ptrs
{
vector_ptrs deep_cpy;
deep_cpy.reserve(m_ts.size());
for(const auto &elem : m_ts){
deep_cpy.push_back(elem->clone());
}
return deep_cpy;
}
template<typename float_t>
std::unique_ptr<transform<float_t>> transform<float_t>::create(trans_type tt)
{
switch (tt) {
case trans_type::TT_null:
return std::make_unique<null_trans<float_t>>();
case trans_type::TT_twice_fisher:
return std::make_unique<twice_fisher_trans<float_t>>();
case trans_type::TT_logit:
return std::make_unique<logit_trans<float_t>>();
case trans_type::TT_log:
return std::make_unique<log_trans<float_t>>();
}
throw std::invalid_argument("that transform type was not accounted for");
}
template<typename float_t>
void transform_container<float_t>::add_transform(trans_type tt)
{
m_ts.push_back(transform<float_t>::create(tt));
}

Making a safe buffer holder in C++

There are situations in which I need to pass a char* buffer back and forth. My idea is to create an object which can hold the object that owns the data, but also expose the data as char* for someone to read. Since this object holds the owner, there are no memory leaks because the owner is destructed with the object when it's no longer necessary.
I came with the implementation below, in which we have a segfault that I explain why it happens. In fact it's something that I know how to fix but it's something that my class kinda lured me into doing. So I consider what I've done to be not good and maybe there's a better way of doing this in C++ that is safer.
Please take a look at my class that holds the buffer owner and also holds the raw pointer to that buffer. I used GenericObjectHolder to be something that holds the owner for me, without my Buffer class being parametrized by this owner.
#include <iostream>
#include <string>
#include <memory>
#include <queue>
//The library:
class GenericObjectHolder
{
public:
GenericObjectHolder()
{
}
virtual ~GenericObjectHolder() {
};
};
template <class T, class Holder = GenericObjectHolder>
class Buffer final
{
public:
//Ownership WILL be passed to this object
static Buffer fromOwned(T rawBuffer, size_t size)
{
return Buffer(std::make_unique<T>(rawBuffer), size);
}
//Creates a buffer from an object that holds the buffer
//ownership and saves the object too so it's only destructed
//when this buffer itself is destructed
static Buffer fromObject(T rawBuffer, size_t size, Holder *holder)
{
return Buffer(rawBuffer, std::make_unique<T>(rawBuffer), size, holder);
}
//Allocates a new buffer with a size
static Buffer allocate(size_t size)
{
return Buffer(std::make_unique<T>(new T[size]), size);
}
~Buffer()
{
if (_holder)
delete _holder;
}
virtual T data()
{
return _rawBuffer;
}
virtual size_t size() const
{
return _size;
}
Buffer(T rawBuffer, std::unique_ptr<T> buffer, size_t size)
{
_rawBuffer = rawBuffer;
_buffer = std::move(buffer);
_size = size;
}
Buffer(T rawBuffer, std::unique_ptr<T> buffer, size_t size, Holder *holder)
{
_rawBuffer = rawBuffer;
_buffer = std::move(buffer);
_size = size;
_holder = holder;
}
Buffer(const Buffer &other)
: _size(other._size),
_holder(other._holder),
_buffer(std::make_unique<T>(*other._buffer))
{
}
private:
Holder *_holder;
T _rawBuffer;
std::unique_ptr<T> _buffer;
size_t _size = 0;
};
//Usage:
template <class T>
class MyHolder : public GenericObjectHolder
{
public:
MyHolder(T t) : t(t)
{
}
~MyHolder()
{
}
private:
T t;
};
int main()
{
std::queue<Buffer<const char*, MyHolder<std::string>>> queue;
std::cout << "begin" << std::endl;
{
//This string is going to be deleted, but `MyHolder` will still hold
//its buffer
std::string s("hello");
auto h = new MyHolder<std::string>(s);
auto b = Buffer<const char*, MyHolder<std::string>>::fromObject(s.c_str(),s.size(), h);
queue.emplace(b);
}
{
auto b = queue.front();
//We try to print the buffer from a deleted string, segfault
printf(b.data());
printf("\n");
}
std::cout << "end" << std::endl;
}
As you see, the s string is copied inside the object holder but gets destructed right after it. So when I try to access the raw buffer that buffer owns I get a segfault.
Of course I could simply copy the buffer from the s string into a new buffer inside my object, but It'd be inefficient.
Maybe there's a better way of doing such thing or maybe there's even something ready in C++ that does what I need.
PS: string is just an example. In pratice I could be dealing with any type of object that owns a char* buffer.
Live example: https://repl.it/repls/IncredibleHomelySdk
Your core problem is that you want your Holder to be moveable. But when the Owner object moves, the buffer object might also move. That will invalidate your pointer. You can avoid that by putting the owner in a fixed heap location via unique_ptr:
#include <string>
#include <memory>
#include <queue>
#include <functional>
template <class B, class Owner>
class Buffer
{
public:
Buffer(std::unique_ptr<Owner>&& owner, B buf, size_t size) :
_owner(std::move(owner)), _buf(std::move(buf)), _size(size)
{}
B data() { return _buf; }
size_t size() { return _size; }
private:
std::unique_ptr<Owner> _owner;
B _buf;
size_t _size;
};
//Allocates a new buffer with a size
template<typename T>
Buffer<T*, T[]> alloc_buffer(size_t size) {
auto buf = std::make_unique<T[]>(size);
return {std::move(buf), buf.get(), size};
}
Here's a repl link: https://repl.it/repls/TemporalFreshApi
If you want to have a type-erased Buffer, you can do that like this:
template <class B>
class Buffer
{
public:
virtual ~Buffer() = default;
B* data() { return _buf; }
size_t size() { return _size; }
protected:
Buffer(B* buf, size_t size) :
_buf(buf), _size(size) {};
B* _buf;
size_t _size;
};
template <class B, class Owner>
class BufferImpl : public Buffer<B>
{
public:
BufferImpl(std::unique_ptr<Owner>&& owner, B* buf, size_t size) :
Buffer<B>(buf, size), _owner(std::move(owner))
{}
private:
std::unique_ptr<Owner> _owner;
};
//Allocates a new buffer with a size
template<typename T>
std::unique_ptr<Buffer<T>> alloc_buffer(size_t size) {
auto buf = std::make_unique<T[]>(size);
return std::make_unique<BufferImpl<T, T[]>>(std::move(buf), buf.get(), size);
}
Again, repl link: https://repl.it/repls/YouthfulBoringSoftware#main.cpp
You wrote:
There are situations in which I need to pass a char* buffer back and
forth.
and
So I consider what I've done to be not good and maybe there's a better
way of doing this in C++ that is safer.
It's not exactly clear what you are aiming at, but when I have this need i will sometimes use std::vector<char> - a std::vector (and std::string) is a just that: a managed buffer. Calling data() on vector will give you a raw pointer to the buffer to pass on to legacy interfaces etc. or for whatever reason you just need a buffer that you manage yourself. Hint: use resize() or constructor to allocate the buffer.
So you see, there's no need to store the internal pointer of std::string in your example. Instead just call data() on a need basis.
It seems like you are concerned about copies and efficiency. If you use objects that support move semantics and you use the emplace family of functions there shouldn't be any copy-ing going on at least in c++17. All/most containers supports moving as well.
The class std::unique_ptr is already a "buffer holder" that "guarantee delete", no string copies, no dangling references and no seg faults:
#include <iostream>
#include <queue>
#include <memory>
int main()
{
std::queue<std::unique_ptr<std::string>> queue;
std::cout << "begin" << std::endl;
{
auto h = std::make_unique<std::string>("Hello");
queue.emplace( std::move(h) ); // move into the queue without copy
}
{
auto b = std::move(queue.front()); // move out from queue without copy
std::cout << *b << std::endl;
} // when b goes out of scope it delete the string
std::cout << "end" << std::endl;
}
https://godbolt.org/z/neP838

Framework applications using interface without heap memory allocation?

I am trying to create a framework for applications to use in my microprocessors. I am using Arduino IDE to compile and deploy the programs.
Since the microprocessors often have low heap memory, I want to only use stack memory if possible.
Minimial example:
The whole example code can be seen here.
I will describe the parts I think is most interesting.
iMinExApplication (interface):
class iMinExApplication
{
public:
virtual void initialize() = 0; // pure virtual
virtual void execute() = 0; // pure virtual
virtual ~iMinExApplication() = default; // Virtual destructor
};
tMinExApplication (extension of interface, only used by the framework):
class tMinExApplication
{
public:
...
tMinExApplication(iMinExApplication* app, const char name[]) : App(app)
{
strcpy(Name, name);
};
...
void execute() { App->execute(); };
private:
iMinExApplication* App;
char Name[32];
};
tMinExCoordinator (master, calling added apps)
class tMinExCoordinator
{
public:
...
void addApp(iMinExApplication* app, const char name[])
{
tMinExApplication* tmpPtr = new tMinExApplication(app, name); // HERE!
Applications[++NumApps] = tmpPtr;
tmpPtr = nullptr;
};
...
void runApps()
{
for (auto& app : Applications) {
// Frequency check
// ...
app->execute();
}
};
private:
tMinExApplication* Applications[];
int NumApps;
};
tMyApp (user defined app, using the inherited interface)
class tMyApp : public iMinExApplication {
...
minExSketch (Arduino IDE sketch)
#include "tMinExClasses.hpp"
#include "tMyApp.hpp"
tMinExCoordinator coordinator{};
tMyApp tmpApp{};
void setup() {
Serial.begin(9600);
coordinator.addApp(&tmpApp, "TEST");
coordinator.initializeApps();
}
void loop() {
coordinator.runApps();
}
The above works. But the apps are allocated in heap memory, since it uses the keyword new ('HERE!' in the tMinExCoordinator class definition, line 57 in tMinExClasses.hpp).
I cannot seem to get it to work without it.
In what other way could I implement this, but only allocating memory in stack memory?
Requirements:
Stack memory allocation
The interface is to be used.
I have though of smart pointers, but am unsure if they use heap memory or not. Also, I wanted the minimal example as clean as possible.
I cannot seem to get it to work without it. In what other way could I implement this, but only allocating memory in stack memory?*
You can pre-allocate a byte array of sufficient size, and then use placement-new to construct objects inside of that array (see std::aligned_storage to help you with that). Polymorphism only requires pointers/references to work at runtime, not dynamic alllocations.
template<std::size_t MaxApps>
class tMinExCoordinator
{
public:
...
tMinExCoordinator()
{
Applications = reinterpret_cast<tMinExApplication*>(appBuffer);
}
~tMinExCoordinator()
{
for (std::size_t i = 0; i < NumApps; ++i)
Applications[i].~tMinExApplication();
}
void addApp(iMinExApplication* app, const char name[])
{
if (NumApps >= MaxApps)
throw std::length_error("");
new (&appBuffer[NumApps]) tMinExApplication(app, name);
++NumApps;
}
...
void runApps()
{
for (std::size_t i = 0; i < NumApps; ++i)
{
auto& app = Applications[i];
// Frequency check
// ...
app.execute();
}
}
private:
typename std::aligned_storage<sizeof(tMinExApplication), alignof(tMinExApplication)>::type appBuffer[MaxApps];
tMinExApplication* Applications;
std::size_t NumApps = 0;
};
tMinExCoordinator<1> coordinator{};
...
The std::aligned_storage documentation linked above has an example static_vector class that uses a fixed memory buffer, which will be on the stack if the vector is constructed on the stack:
#include <iostream>
#include <type_traits>
#include <string>
template<class T, std::size_t N>
class static_vector
{
// properly aligned uninitialized storage for N T's
typename std::aligned_storage<sizeof(T), alignof(T)>::type data[N];
std::size_t m_size = 0;
public:
// Create an object in aligned storage
template<typename ...Args> void emplace_back(Args&&... args)
{
if( m_size >= N ) // possible error handling
throw std::bad_alloc{};
// construct value in memory of aligned storage
// using inplace operator new
new(&data[m_size]) T(std::forward<Args>(args)...);
++m_size;
}
// Access an object in aligned storage
const T& operator[](std::size_t pos) const
{
// note: needs std::launder as of C++17
return *reinterpret_cast<const T*>(&data[pos]);
}
// Delete objects from aligned storage
~static_vector()
{
for(std::size_t pos = 0; pos < m_size; ++pos) {
// note: needs std::launder as of C++17
reinterpret_cast<T*>(&data[pos])->~T();
}
}
};
You can use that class in your coordinator, with some minor additions to it so it can work with loops, eg:
template<class T, std::size_t N>
class static_vector
{
// properly aligned uninitialized storage for N T's
typename std::aligned_storage<sizeof(T), alignof(T)>::type data[N];
std::size_t m_size = 0;
public:
// Create an object in aligned storage
template<typename ...Args> void emplace_back(Args&&... args)
{
if( m_size >= N ) // possible error handling
throw std::bad_alloc{};
// construct value in memory of aligned storage
// using inplace operator new
new(&data[m_size]) T(std::forward<Args>(args)...);
++m_size;
}
// Access an object in aligned storage
T& operator[](std::size_t pos)
{
// note: needs std::launder as of C++17
return *reinterpret_cast<T*>(&data[pos]);
}
const T& operator[](std::size_t pos) const
{
// note: needs std::launder as of C++17
return *reinterpret_cast<const T*>(&data[pos]);
}
std::size_t size() const { return m_size; }
std::size_t capacity() const { return N; }
// iterator access to objects
T* begin()
{
// note: needs std::launder as of C++17
return reinterpret_cast<T*>(&data[0]);
}
T* end()
{
// note: needs std::launder as of C++17
return reinterpret_cast<T*>(&data[m_size]);
}
const T* cbegin() const
{
// note: needs std::launder as of C++17
return reinterpret_cast<const T*>(&data[0]);
}
const T* cend() const
{
// note: needs std::launder as of C++17
return reinterpret_cast<const T*>(&data[m_size]);
}
// Delete objects from aligned storage
~static_vector()
{
for(std::size_t pos = 0; pos < m_size; ++pos) {
// note: needs std::launder as of C++17
reinterpret_cast<T*>(&data[pos])->~T();
}
}
};
template<std::size_t MaxApps>
class tMinExCoordinator
{
public:
...
void addApp(iMinExApplication* app, const char name[])
{
Applications.emplace_back(app, name);
}
...
void runApps()
{
for (auto& app : Applications)
{
// Frequency check
// ...
app.execute();
}
}
private:
static_vector<tMinExApplication, MaxApps> Applications;
};
I have though of smart pointers, but am unsure if they use heap memory or not.
By default, they rely on new and delete, and thus dynamic memory. Though, you can supply them with pointers to stack memory, if you also supply them with custom deleters that won't free that memory.

How to forward declare custom unique_ptr for shared memory

I've taken the example below from Dr. Rian Quinn's book "Hands-On System Programming with C/C++" modified just a bit. It wraps mmap with a unique_ptr{}. It works almost just like I need. I would like to forward declare the pointer to the mapped memory so I can use it as a private class member. My application is multi-task, each single-threaded, hard real-time with shared memory for cross-task communication. Dr. Quinn has a second example with shared memory that's a little longer than the one shown here but it this one illustrates the problem. The shm_open/mmap is relatively expensive time-wise. I need it to be done once during setup and have no idea how to go about it. I know how to do this with raw pointers. I'm using g++ 4.8.5.
I've tried:
std::unique_ptr<myStruct,mmap_deleter> ptr;
Which results in:
/usr/include/c++/4.8.2/tuple:132:22: error: no matching function for call to ‘mmap_deleter::mmap_deleter()’
: _M_head_impl() { }
#include <memory>
#include <iostream>
#include <string.h>
#include <sys/mman.h>
constexpr auto PROT_RW = PROT_READ | PROT_WRITE;
constexpr auto MAP_ALLOC = MAP_PRIVATE | MAP_ANONYMOUS;
class mmap_deleter
{
std::size_t m_size;
public:
mmap_deleter(std::size_t size) :
m_size{size}
{ }
void operator()(void *ptr) const
{
munmap(ptr, m_size);
}
};
template<typename T>
auto mmap_unique()
{
if (auto ptr = mmap(0, sizeof(T), PROT_RW, MAP_ALLOC, -1, 0)) {
auto obj = new (ptr) T(args...);
auto del = mmap_deleter(sizeof(T));
return std::unique_ptr<T, mmap_deleter>(obj, del);
}
throw std::bad_alloc();
}
struct myStruct{
double foo;
double bar;
};
// Forward declare pointer, neither compiles
std::unique_ptr<myStruct> ptr;
// or
// std::unique_ptr<myStruct,mmap_deleter> ptr;
int main()
{
ptr = mmap_unique<myStruct>();
ptr->foo = 55.;
std::cout << ptr->foo << '\n';
}
Here's a silly example that will compile and run that uses a raw pointer that illustrates what I want to do with a smart pointer.
// myClass.h
class myClass
{
public:
myClass();
~myClass();
int get_i();
int get_j();
private:
void myFunc1();
void myFunc2();
void myFunc3();
struct myStruct{
int i;
int j;
};
// FORWARD Declaration of ptr here!!!!!!!!!!!!!!!!!!!!!
// I would like to use a smart pointer
myStruct* ptr_myStruct{nullptr};
};
#include <sys/mman.h>
#include <iostream>
#include <string.h>
#include <cerrno>
//#include "myClass.h"
myClass::myClass(){
// Set the pointer to the mmap'ed address
ptr_myStruct = (myStruct*)mmap(NULL,sizeof(myStruct),PROT_READ|PROT_WRITE,MAP_SHARED|MAP_ANONYMOUS, -1, 0);
memset(ptr_myStruct,0,sizeof(myStruct));
// The three member functions use ptr_myStruct
myFunc1();
myFunc2();
myFunc3();
}
myClass::~myClass(){
munmap(ptr_myStruct,sizeof(myStruct));
ptr_myStruct = nullptr;
}
void myClass::myFunc1(){
ptr_myStruct->i++;
}
void myClass::myFunc2(){
ptr_myStruct->j++;
}
void myClass::myFunc3(){
ptr_myStruct->i++;
}
int myClass::get_i(){return ptr_myStruct->i;}
int myClass::get_j(){return ptr_myStruct->j;}
int main(){
myClass a;
std::cout<< a.get_i()<<" "<<a.get_j()<<"\n";
}
After some massaging your code does compile and work (I added some debug prints to demonstrate it), see the live example. (Also, be aware that mmap_deleter doesn't call obj's destructor, but it should).
Given that you use C++14, I would suggest to remove mmap_deleter and simplify the code as follows:
template <typename T>
using unique_mapped_ptr = std::unique_ptr<T, void(*)(T*)>;
template<typename T, typename ...Args>
unique_mapped_ptr<T> mmap_unique(Args... args)
{
constexpr auto PROT_RW = PROT_READ | PROT_WRITE;
constexpr auto MAP_ALLOC = MAP_PRIVATE | MAP_ANONYMOUS;
if (auto ptr = mmap(0, sizeof(T), PROT_RW, MAP_ALLOC, -1, 0)) {
return {
new (ptr) T{args...},
[](T*p) {
p->~T();
munmap(p, sizeof(T));
}
};
}
throw std::bad_alloc();
}
You can then use unique_mapped_ptr<myStruct> to define pointers to mmapped objects.
See the example with myClass.
The line
std::unique_ptr<myStruct,mmap_deleter> ptr;
tries to default construct a mmap_deleter, because that is a definition of an object. Your size_t constructor suppresses the compiler generated default (which is good for you here).
You can instead provide it as a template parameter, which also allows you to apply ~T to your objects as required.
template <typename T>
struct mmap_deleter
{
void operator()(T* ptr) const
{
ptr->~T();
munmap(ptr, sizeof(T));
}
};
template<typename T, typename... Args>
std::unique_ptr<T, mmap_deleter<T>> mmap_unique(Args&&... args)
{
if (auto ptr = mmap(0, sizeof(T), PROT_RW, MAP_ALLOC, -1, 0)) {
return { new (ptr) T(std::forward<Args>(args)...) };
}
throw std::bad_alloc();
}

How to create pool of contiguous memory of non-POD type?

I have a scenario where I have multiple operations represented in the following way:
struct Op {
virtual void Run() = 0;
};
struct FooOp : public Op {
const std::vector<char> v;
const std::string s;
FooOp(const std::vector<char> &v, const std::string &s) : v(v), s(s) {}
void Run() { std::cout << "FooOp::Run" << '\n'; }
};
// (...)
My application works in several passes. In each pass, I want to create many of these operations and at the end of the pass I can discard them all at the same time. So I would like to preallocate some chunk of memory for these operations and allocate new operations from this memory. I came up with the following code:
class FooPool {
public:
FooPool(int size) {
foo_pool = new char[size * sizeof(FooOp)]; // what about FooOp alignment?
cur = 0;
}
~FooPool() { delete foo_pool; }
FooOp *New(const std::vector<char> &v, const std::string &s) {
return new (reinterpret_cast<FooOp*>(foo_pool) + cur) FooOp(v,s);
}
void Release() {
for (int i = 0; i < cur; ++i) {
(reinterpret_cast<FooOp*>(foo_pool)+i)->~FooOp();
}
cur = 0;
}
private:
char *foo_pool;
int cur;
};
This seems to work, but I'm pretty sure I need to take care somehow of the alignment of FooOp. Moreover, I'm not even sure this approach is viable since the operations are not PODs.
Is my approach flawed? (most likely)
What's a better way of doing this?
Is there a way to reclaim the existing memory using unique_ptrs?
Thanks!
I think this code will have similar performance characteristics without requiring you to mess around with placement new and aligned storage:
class FooPool {
public:
FooPool(int size) {
pool.reserve(size);
}
FooOp* New(const std::vector<char>& v, const std::string& s) {
pool.emplace_back(v, s); // in c++17: return pool.emplace_back etc. etc.
return &pool.back();
}
void Release() {
pool.clear();
}
private:
std::vector<FooOp> pool;
}
The key idea here being that your FooPool is essentially doing what std::vector does.