On 11 Jul 2014 at 21:06, Daniel James wrote:
My understanding is that the allocators have to be used for all dynamic allocation. If this is not explicitly worded in the standard, then it should be. Otherwise allocators simply are not as useful with any other interpretation.
I assume by allocators you mean specifically STL allocators?
I looked this up earlier, as I thought the same. 23.2.1.7 says:
"Unless otherwise specified, all containers defined in this clause obtain memory using an allocator (see 17.6.3.5)."
Which suggests to me that all allocation is done using the allocator. I suppose debug info could be considered something that isn't obtained by the container, as it can be external, but I wouldn't have thought that for things like buckets.
The standard definitely means an STL allocator, not simply "an allocator"? It's not just debug info though. I can think of a number of STL containers which could use non-STL allocation for internal stuff - for example, if you create a threadsafe STL container you could allocate an internal mutex, and it would seem excessive to require using an externally supplied allocator for that too. Furthermore, a std::mutex under the hood will almost certainly do some more allocation. You might argue this isn't really allocation of memory. So to counterexample, what about a STL container of shared memory regions? Or a STL container of memory mapped files? You'd want the allocator - given it has 4Kb granularity - to only be used for value types only. I suppose you could specialise the rebind to avoid this happening, but we're beginning to chase our tail now.
23.2.1.3 says:
"For the components affected by this subclause that declare an allocator_type, objects stored in these components shall be constructed using the allocator_traits
::construct function and destroyed using the allocator_traits ::destroy function (20.7.8.2). These functions are called only for the container´s element type, not for internal types used by the container." But that's specifying construction, not allocation (btw. I get this wrong in unordered, I'll fix it soon).
I have been lazy as it's test code, and implemented a move assignment like this for an internal item_type due to value_type.first being const: struct item_type { value_type p; size_t hash; item_type() : hash(0) { } item_type(value_type &&_p, size_t _hash) BOOST_NOEXCEPT : p(std::move(_p)), hash(_hash) { } item_type(item_type &&o) BOOST_NOEXCEPT : p(std::move(o.p)), hash(o.hash) { } item_type &operator=(item_type &&o) BOOST_NOEXCEPT { this->~item_type(); new (this) item_type(std::move(o)); return *this; } Which would normally be unsafe, except everything is noexcept, so I actually think this is okay except for the fact that the allocator's construct and destroy aren't being invoked.
Did I miss anything? I don't claim any expertise here.
Me neither. When do C++ programmers normally implement STL containers as part of their normal day job? Probably only Stephan. Anyway, they're a bitch to do correctly and keep performance reasonable. Niall -- ned Productions Limited Consulting http://www.nedproductions.biz/ http://ie.linkedin.com/in/nialldouglas/