Placing a new and perfect shipment

I have the following code that intends to create an array, but without initializing its default objects. I would like to ideally move to a new place, which seems to happen, but I found that the object destructor is called inside the emplace function.

#include <iostream>
#include <memory> // std::uninitialized_copy, std::allocator...
#include <utility> // std::move...
#include <bitset>


struct Int {

    int i;

    Int ( ) : i ( -1 ) { std::cout << "default constructed\n"; }
    Int ( const int i_ ) : i ( i_ ) { std::cout << i << " constructed\n"; }
    Int ( Int && int_ ) : i ( std::move ( int_.i ) ) { std::cout << i << " move constructed\n"; }
    Int ( const Int & int_ ) : i ( int_.i ) { std::cout << i << " copy constructed\n"; }
    ~Int ( ) { std::cout << i << " destructed\n"; i = -1; }
};


template <typename T, size_t S = 64>
class NoInitArray {

    std::bitset<S> m_used;

    T *m_array = reinterpret_cast < T* > ( ::operator new ( sizeof ( T ) * S ) );

public:

    T const &operator [ ] ( const size_t idx_ ) const {

        return m_array [ idx_ ];
    }

    NoInitArray ( ) { }

    ~NoInitArray ( ) {

        for ( size_t idx = 0; idx < S; ++idx ) {

            if ( m_used [ idx ] ) {

                reinterpret_cast< const T* > ( m_array + idx )->~T ( );
            }
        }
    }

    template<typename ...Args>
    void emplace ( const size_t idx_, Args &&... value_ ) {

        std::cout << "start emplace\n";

        m_used [ idx_ ] = 1;

        new ( m_array + idx_ ) T ( std::forward<T> ( value_ ) ... );

        std::cout << "end emplace\n";
    }
};


int main ( ) {

    NoInitArray<Int> nia;

    nia.emplace ( 0, 0 );
    nia.emplace ( 1, 1 );

    std::cout << nia [ 1 ].i << std::endl;

    nia.emplace ( 2, 2 );

    return 0;
}

The result of starting this program is as follows:

start emplace
0 constructed
0 move constructed
0 destructed
end emplace
start emplace
1 constructed
1 move constructed
1 destructed
end emplace
1
start emplace
2 constructed
2 move constructed
2 destructed
end emplace
0 destructed
1 destructed
2 destructed

This shows that objects are built once and destroyed twice (which is obviously UB), once inside the emplace function, and then once upon destruction of NoInitArray.

Question: "Why is the destructor of my Int object called inside the emplace function"?

Compiler, the latest Clang / LLVM on Windhoze.

EDIT1: I added move and copy constructors to the Int structure, now the counters match, i.e. 2 designs and 2 destruction.

EDIT2: new ( m_array + idx_ ) T ( std::forward<T> ( value_ ) ... ); new ( m_array + idx_ ) T ( value_ ... ); / .

EDIT3: . , NoInitArray() . delete m_array - , ( Clang/LLVM) m_array [0] (, , , UB). std:: malloc/std:: free, , , , , , .

+4
2

" , ", . X move constructed , .

new ( m_array + idx_ ) T ( std::forward<T> ( value_ ) ... );

new ( m_array + idx_ ) T ( std::forward<Args&&> ( value_ )... );

std::forward<T>(value_) , T=Int, , .

2 std::forward. , , , emplace,

    nia.emplace ( 0, Int(0) );

std::forward, new T(value_...) , new T(std::forward<Args&&>(value_)...) .

-2

new T(std::forward<Args>(value_)...). @ .

+4

, : std::forward<T> ( value_ ) new ( m_array + idx_ ) T ( std::forward<T> ( value_ ) ... ).

std::forward<T>(value_) T.

+4

All Articles