I'm looking into using mbed's MemoryPool API, however it seems to be oriented for simple POD types.
Inspecting the source of MemoryPool.h seems to show that it's just taking memory blocks and presenting as is (or zeroing the block if using calloc) and not doing placement new. I tried to follow the implementation, but got a bit lost in the syscall/weak-link maze.
My question: Is this MemoryPool implementation usable with non-trivial C++ classes? That is, if I make an allocation request, will the object constructor be called? Or do I need to create an adapted MemoryPool to perform placement new operations (and the corresponding destructor calls) in order to obtain properly initialized and constructed objects?
I've opened an issue over at Github - https://github.com/ARMmbed/mbed-os/issues/5891
What has been reported so far reinforces what #Pharap has said in their answer.
if I make an allocation request, will the object constructor be called?
It would seem not.
Although I cannot find the source code for the osMemoryPoolAlloc function, there are a few other giveaways.
Firstly as you mentioned, calling memset(item, 0, sizeof(T)); as the code does in calloc does indeed violate safe construction and destruction.
Secondly, the fact that the result of osMemoryPoolAlloc is being cast to (T*) implies that it returns a void * and knows nothing about the type it's allocating memory for other than perhaps its size.
do I need to create an adapted MemoryPool to perform placement new operations (and the corresponding destructor calls) in order to obtain properly initialized and constructed objects?
Yes, you would.
But as #Daniel Langr mentions, there could potentially be alignment issues involved.
For what it's worth there's a comment at the bottom of the code that says:
/* osMemoryPoolNew requires that pool block size is a multiple of 4 bytes. */
and I believe most arm devices are 32-bit so I would assume it's probably safe to use placement new to create a type that has an alignment of 4 (which you can check with alignof.
However, my advice is to raise an issue about this over on the github page.
It seems that the code is not sufficiently documented, so without intimate knowledge of the code it would be hard to give a straight answer to your second question.
(Note that if the memory returned is suitable aligned then you could create a simple wrapper template class that adheres to the rules of an allocator. This would permit use with allocator-enabled containers, though they would be limited in size as a result.)
Related
I'm wrestling with some pain being caused by std::allocator_traits::construct. In order for a container to be a "conforming" user of the allocator concept, it needs to use construct rather than placement new to construct objects. This is very sticky for me. Currently I have a class (class A) that is designed to be allocator aware, and at some point it needs to create another instance of some other class (class B) in allocated memory. The problem is that class B implements the construction of the new object. If I could use placement new, this wouldn't be an issue: A would handle allocation, pass B the memory address, and B would construct into that. But since the construction needs to be performed via construct, I need to inject the allocator type into B, templating it, which creates a huge mess.
It's bad enough that I am seriously considering just using placement new, and static asserting that my instance of the allocator does not have a construct method (note that the static construct function calls the instance method if it exists, otherwise it calls placement new). I have never felt the tiniest urge to write a construct method for an allocator. The cost of making this part of the allocator concept seems very high to me; construction has gotten entangled with allocation, where allocators were supposed to help separate them. What justifies the existence of construct/destruct? Insight into the design decision, examples of real (not toy) use cases, or thoughts on the gravity of electing to simply use placement new appreciated.
There is a similar question; std::allocator construct/destroy vs. placement new/p->~T(). It was asked quite a long time ago, and I don't find the answer accepted there as sufficient. Logging is a bit trite as a use case, and even then: why is the allocator logging the actual construction of objects? It can log allocations and deallocations in allocate and deallocate, it doesn't answer the question in the sense of: why was construction made a province of the allocator in the first place? I'm hoping to find a better answer; it's been quite a few years and much about allocators has changed since then (e.g. allocators being stateful since 11).
A few points:
There really isn't a std container concept. The container requirements tables in the standard are there to document the containers specified by the standard.
If you have a container that wants to interact with std::allocator_traits<Alloc>, all you have to do is assume that Alloc conforms to the minimum C++11 allocator requirements and interact with it via std::allocator_traits<Alloc>.
You are not required to call std::allocator_traits<Alloc>::construct.
You are forbidden from calling Alloc::construct because it may not exist.
The standard-specified containers are required to call std::allocator_traits<Alloc>::construct only for container::value_type, and are forbidden from using std::allocator_traits<Alloc>::construct on any other types the container may need to construct (e.g. internal nodes).
Why was construct included in the "allocator concept" way back in C++98?
Probably because the committee at the time felt that this would ease dealing with x86 near and far pointers -- a problem that no longer exists today.
That being said, std::scoped_allocator_adaptor is a modern real-world example of an allocator that customizes both construct and destroy. For the detailed specification of those customizations I point you towards the latest C++1z working draft, N4567. The spec is not simple, and that is why I'm not attempting to reproduce it here.
I was reading the TC++PL about the raw_storage_iterator component. Using this component we get performance benefit as it avoids the assignment(more expensive) and uses copy construction. It looked to me that it should be used in the sequence/container where we could have significant number of elements and hence number of assignment calls can be great impact.
Theoretically its clear and it looked to me that this component is useful for container type classes. However I would like to understand where we should use this component(with practical examples) in bit details to get its performance benefit?
Over at cppreference there is sample code.
You can allocate aligned blocks of uninitialized memory through a number of mechanisms. Cppreferences uses std::get_temporary_buffer<T> to allocate such a buffer.
You can then make a pointer to these elements. The pointer's type is a bit misleading, because it isn't a pointer to a valid T, but rather to a block of memory that is suitable for constructing a T.
The std::raw_storage_iterator can be populated with that T* and told to output to it. You can then feed that iterator to an algorithm that expects a conventional output iterator, and things go smoothly.
If you tried to do this without the raw_storage_iterator, you'd be assigning to a non-constructed T, which is undefined behavior. As an alternative, you could construct the T's before outputting to them -- but that is wasteful, as it constructs the object twice.
The basic idea is to allow use of uninitialized output buffers with near perfect efficiency in standard algorithms. It isn't something you should be using outside of some serious code microoptimization.
What are the pros and cons of
using Plain Old Data (POD)
structs\classes in C++?
In what cases should one prefer using
them over non-PODs?
Specifically,
do PODs have advantages while working
with serialization frameworks?
Perhaps when working cross-platform
and cross-language?
If you have a gazillion small objects, ensuring that those objects are POD can be a huge advantage.
You can calloc() or malloc() a large chunk of them, saving you a gazillion calls to constructors.
For persistence, rather than streaming out the objects one at a time, you can use fwrite() and fread() entire chunk of them for speed.
The disadvantage is, you have to keep your mind flexible to handle non-OOP PODs in your code. PODs are a fallback from old-style C code where you know and care about the layout of your data. When that layout is well-defined, you may optimize by working chunks of memory rather than lots of little pieces.
Please note that what I describe above applies to trivially laid out structures. In other words, if you call type_trait's std::is_trivially_copyable() on this type, you will get true. The requirements for POD are actually even stronger than that of trivially-copiable structures. So what I just described above applies to all PODs and even some non-PODs which happen to be trivially-copiable.
There is one advantage of POD in conjunction with constants.
If you declare/define a constant and you use a POD type for it the whole POD is put into the (constant) data section of the executable/library and is available after loading.
If you use a non-POD the constructor must run to initialize it. Since the order of running constructors of static classes in C++ is undefined you cannot access static A from static B's constructor or any code that is invoked from within static B's constructor.
So using PODs in this case is safe.
PODs can be used in C interfaces which means that you can have a library written in C++ but with a C interface which can advantageous.
The disadvantage is that you can't use a constructor to put burden of initialization onto the type itself - the user code will have to take care of that.
pods have some subtle advantage.
I don't know any portable way to calculate memory size required
for new[] operator if array elements are non-pod,
so it is dificult to use safely placement new[] operator for such an array.
If nonpod structure has a destructor, new[] needs extra space to store array size, but this extra size is implementation-dependent (althogh usually it is sizeof(size_t) + (perhaps) some padding to provide proper alignment)
Would it be possible in C++ to create a custom allocator that works simply like this:
{
// Limit memory to 1024 KB
ScopedMemoryPool memoryPool(1024 * 1024);
// From here on all heap allocations ('new', 'malloc', ...) take memory from the pool.
// If the pool is depleted these calls result in an exception being thrown.
// Examples:
std::vector<int> integers(10);
int a * = new int [10];
}
I couldn't find something like this in the boost libraries, or anywhere else.
Is there a fundamental problem that makes this impossible?
You would need to create a custom allocator that you pass in as a template param to vector. This custom allocator would essentially wrap the access to your pool and do whatever size validations that it wants.
Yes you can make such a construct, it's used in many games, but you'll basically need to implement your own containers and call memory allocation methods of that pool that you've created.
You could also experiment with writing a custom allocator for the STL containers, although it seems that that sort of work is generally advised against. (I've done it before and it was tedious, but I don't remember any specific problems.)
Mind- writing your own memory allocator is not for the faint of heart. You could take a look at Doug Lea's malloc, which provides "memory spaces", which you could use in your scoping construct somehow.
I will answer a different question. Look at 'efficient c++' book. One of the things they discuss is implementing this kind of thing. That was for a web server
For this particular thing you can either mess at the c++ layer by overriding new and supplying custom allocators to the STL.
Or you can mess at the malloc level, start with a custom malloc and work from there (like dmalloc)
Is there a fundamental problem that makes this impossible?
Arguing about program behavior would become fundamentally impossible. All sorts of weird issues will come up. Certain sections of the code may or may not execute though this will seeminly have no effect on the next sections which may work un-hindered. Certain sections may always fail. Dealing with the standard-library or any other third party library will become extremely difficult. There may be fragmentations at run-time at times and at times not.
If intent is that all allocations within that scope occur with that allocator object, then it's essentially a thread-local variable.
So, there will be multithreading issues if you use a static or global variable to implement it. Otherwise, not a bad workaround for the statelessness of allocators.
(Of course, you'll need to pass a second template argument eg vector< int, UseScopedPool >.)
There was an article i found long ago (i cant find it ATM) which states reasons why the new keyword in C++ is bad. I cant remember all of the reasons but the two i remember most is you must match new with delete, new[] with delete[] and you cannot use #define with new as you could with malloc.
I am designing a language so i like to ask how would you change the C++ language so new is more friendly. Feel free to state problems with new and articles. I wish i can find the article link but i remember it was long and was written by a professor at (IIRC) a known school.
I cannot see any reason to replace the new keyword with something else (and seems to be that C++ committee agree with me). It is clear and makes what it should. You could override operator new in your class, no need to use defines.
To eliminate new[]/delete[] problem you could use std::vector.
If you want to use smart pointer you could use it, but I want to control when smart pointer will be used. That's why I like how it works in C++ — high level behavior with ability to control low level details.
Problem match new, delete, new[], delete[]
Not really a big deal.
You should be wrapping memory allocation inside a class so this does not really affect normal users. A single obejct can be wrapped with a smart pointer. While an array can be represented by std::Vector<>
cannot use #define with new as you could with malloc.
The reason to mess with malloc like this was to introduce your own memory management layer between your app and the standard memory management layer. This is because in C you were not allowed to write your own version of malloc. In C++ it is quite legal to write your own version of the new which makes this trick unnecessary.
I'd give it the semantics of new in C# (more or less):
Allocates memory for the object.
Initializes the memory by setting the member variables to their default values (generally 0 for values, null for references).
Initializes the object's dynamic binding mechanism (vtables in C++, type def tables for managed VMs).
Calls the constructor, at which point virtual calls work as expected.
For a language without garbage collection (eww for a new language at this point), return a smart_ptr or similar from the call.
Also, make all objects either value types or reference types, so you don't have to keep an explicit smart_ptr. Only allow new to heap-allocate for reference types, and make sure it contains information to properly call the destructor. For value types, new calls the constructor on memory from the stack.
Use Garbage Collection so that you never need to match new with anything.
By using the STL container classes and the various boost:smart_ptrs, there's little need to ever explicitly call new or delete in your C++ code.
The few places you might need to call new (e.g, to initialize a smart pointer) use the Named Constructor Idiom to return your class type pointer wrapped in, e.g., a boost:shared_ptr.
But C++ and the STL work very very hard to allow you to treat most objects as value objects, so you can construct objects rather than pointers and just use them.
Given all this, there's little need to replace the new operator -- and doing so would introduce a host of problems, whether by requiring a garbage collector, or by reducing the fine low-level control C++ offers programmers.
If your new language is garbage collected, you can avoid the new keyword. Thats what Python did (and Lisp did almost 5 decades ago!). Also see an answer provided by Peter Norvig for a similar question here. (Is no "news" good news?)
Sometimes you want to replace the constructor with a factory. This is a well known refactoring. Replace Constructor With Factory Method. So perhaps this is what the article meant?
Incidentally you will often see straight calls to new being replaced with a Factory Method.
DI frameworks such as Unity take this concept to another level. As you can see in the following C# code, there is no "new" applied to create the IMyClass interface:
IUnityContainer myContainer = new UnityContainer();
myContainer.RegisterType<IMyClass, SomeClass>();
IMyClass thing = myContainer.Resolve<IMyClass>();
The reason that C++ has a separate new operator ( or C malloc ) is primarily so that objects can be created whose lifetimes exceed the scope of the function which creates them.
If you had tail call elimination and continuations, you wouldn't care - the objects could all be created on the stack and have unlimited extent - an object can exist until you call the continuation that corresponds to the object going out of scope and being destructed. You might then need something to garbage collect or otherwise compress the stack so it doesn't become full of no-longer required objects ( Chicken Scheme and TinyOS 2 are two different examples for giving the effect of dynamic memory without dynamic memory at either runtime or compile time; Chicken Scheme doesn't allow for RAII and TinyOS doesn't allow for true dynamic allocation ), though for a large amount of code such a scheme wouldn't be vastly different to RAII with the facility to chose to change the order the objects are destructed.