简体   繁体   中英

std::for_each() and calling constructors/destructors

I have problems using for_each() and calling constructors/destructors on each element.

For reference, mBegin points to the start of the array, mEnd beyond the last element, mCapacity points to the end of allocated memory.

template <typename T>
void IDMapTree<T>::Grow()
{
    const size_t prevSize = mCapacity - mBegin;
    const size_t newSize = prevSize != 0 ? static_cast<size_t>(1.5f * prevSize) : 1;
    T* newBuffer = static_cast<T*>(mAllocator.Allocate(newSize));

    // initialize new buffer elements with copy constructor using old elements
    uint32_t itemIndex = 0;
    std::for_each(newBuffer, newBuffer + prevSize, [&](T& item) { item.T(*(mBegin + itemIndex++)); });
    // destruct all old elements
    std::for_each(mBegin, mEnd, [](T& item) { item.~T(); });


    // ...
}

This segment compiles fine:

std::for_each(mBegin, mEnd, [](T& item) { item.~T(); });

But this dosn't:

std::for_each(newBuffer, newBuffer + prevSize, [&](T& item) { item.T(*(mBegin + itemIndex++)); });

Not even if I use the default constructor like this:

std::for_each(newBuffer, newBuffer + prevSize, [](T& item) { item.T(); });

The compiler (VS2013) says the following:

error C2039: '__this' : is not a member of 'JonsEngine::SceneNode'
error C2039: 'T' : is not a member of 'JonsEngine::SceneNode'

In this case, T is of type JonsEngine::SceneNode .

What is the issue here? Why dosn't T() resolve to SceneNode() ? Why does the destructor work but not the constructor?

您可以为此使用std::uninitialized_copy()

do it like the stl does it - pass the uninitialized memory chunk as void* ptr and then

::operator new(ptr) T(item)

item should be passed as const reference. (or better - move)

char* newBuffer = static_cast<char*>(mAllocator.Allocate(newSize));
if (newSize % sizeof(T) != 0){
  throw std::runtime_error("memory is not alligned");
}
for (size_t i = 0; i< newSize; i += sizeof(T)){
   ::operator new((void*)ptr) T(item)
}

you should also move the objects instead of copy and deleting the old ones. this will also free you from the need to destruct the old objects.

Edit: I don't see why the downvote when this is the correct way to call any constructor on a pre-allocated memory block. this is the MSVC++ Allocator::construct function which does the same thing

void construct(_Ty *_Ptr, const _Ty& _Val)
    {   // construct object at _Ptr with value _Val
    ::new ((void *)_Ptr) _Ty(_Val);
    } 

want to downvote MSVC++ reputation as well?

You just need to use placement new.

btw your use of destructors is fine:

// destruct all old elements
std::for_each(mBegin, mEnd, [](T& item) { item.~T(); });

The expression item.~T(); is the right way to explicitly call a destructor.

You cannot call constructors this way.

So, placement new could be the way to go:

std::for_each(newBuffer, newBuffer + prevSize, [](T& item) { new (&item) T(); });

btw when using lambdas within a member function you might need to pass this into the capture list.

Why does the destructor work but not the constructor?

Because destructor belongt to instance and constructot belongs to type.

You can't call the constuctor having the instance, you have to call it using name of the type. Anyway, you are doing something strange.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM