Boost logo

Boost :

Subject: Re: [boost] [container] varray aka static_vector
From: Krzysztof Czainski (1czajnik_at_[hidden])
Date: 2013-02-13 08:20:56


2013/2/13 Nevin Liber <nevin_at_[hidden]>

> On 12 February 2013 14:02, Krzysztof Czainski <1czajnik_at_[hidden]> wrote:
>
> > I am not familiar with C++11 initialization syntax details, I only read
> > about that, and I'm stuck with C++03 for now. Are you suggesting, that
> this
> > would mean adding a lot of (too many?) member functions?
>
> There are some corner cases where list initialization behaves differently
> than direct initialization.
>
> Take the following example:
>
> template<typename T>
> struct ListInitializationAllocator
> {
> typedef T value_type;
> typedef typename std::aligned_storage<sizeof(T), alignof(T)>::type
> storage_type;
>
> T* allocate(size_t n) { return static_cast<T*>(static_cast<void*>(::new
> storage_type[n])); }
> void deallocate(T* p, size_t) { ::delete []
> static_cast<storage_type*>(static_cast<void*>(p)); }
>
> template<typename... Args>
> void construct(T* c, Args&&... args)
> { ::new (static_cast<void*>(c)) T{ std::forward<Args>(args)... }; }
> };
>
> vector<vector<int>> vd;
> vd.emplace_back(2);
> assert(2 == vd.back().size());
>
> vector<vector<int>, ListInitializationAllocator<vector<int>>> vl;
> vl.emplace_back(2);
> assert(1 == vl.back().size());
>
> The element in vd is a vector<int> of 2 elements which are
> value-initialized to 0.
> The element in vl is a vector<int> of 1 element copy-initialized to 2.

Thank you, Nevin, for the above example. I think I see your point now.
Furthermore, it gives me an idea:

On 12 February 2013 23:17, Krzysztof Czainski <1czajnik_at_[hidden]> wrote:
> Or perhaps if not a new member function, maybe an overload for a noinit
tag, used like so:
>
> v.emplace_back( noinit );
>
> With noinit defined in the library something like:
> struct noinit_t {};
> noinit_t const noinit = {};

Since the emplace* functions just forward construction args to the
Allocator, the above noinit overloads can be implemented by just supplying
a user Allocator:

#include <boost/container/vector.hpp>
#include <boost/type_traits/is_pod.hpp>
#include <boost/utility/enable_if.hpp>

#include <iostream>
using namespace std;

struct noinit_t {};
noinit_t const noinit = {};

template < class T >
struct MyAllocator : std::allocator<T>
{
    using std::allocator<T>::construct;

    // for v.emplace_back(noinit);
    void construct( T* c, noinit_t/*,
            typename boost::enable_if< boost::is_pod<T> >::type* = 0*/ )
    {}

};

int main()
{
#if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES)
    namespace cont = std;
#else
    namespace cont = boost::container;
#endif

    cont::vector< int, MyAllocator<int> > vi;
    vi.emplace_back(5);
    vi.pop_back();
    vi.emplace_back(noinit);
    assert( 0 != vi.back() );
}

Does this make sense? It works with mingw-4.7.2, but unfortunately it
doesn't compile with -std=c++11, any ideas why?

I also tried the same trick with listinit_t and list initialization (code
attached), as Nevin suggests above, but that also doesn't compile.

I don't think this can be done for resize(), can it?

Cheers,
Kris




Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk