Std::for_each()和调用构造函数/析构函数

std::for_each() and calling constructors/destructors

本文关键字:调用 构造函数 析构函数 for each Std      更新时间:2023-10-16

我在使用for_each()和对每个元素调用构造函数/析构函数时遇到问题。

作为参考,mBegin指向数组的开始,mEnd指向最后一个元素之外,mCapacity指向已分配内存的结束。

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(); });

    // ...
}

这段代码编译得很好:

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

但这不是:

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

即使我像这样使用默认构造函数也不行

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

编译器(VS2013)说:

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

本例中T的类型为JonsEngine::SceneNode

这里有什么问题?为什么T()不能解析为SceneNode() ?为什么析构函数可以工作,而构造函数却不行?

您可以使用std::uninitialized_copy()

像stl那样做-将未初始化的内存块作为void* ptr传递,然后

::operator new(ptr) T(item)

item应该作为const引用传递。(或更好- 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)
}

您还应该移动对象,而不是复制和删除旧的对象。这也将使您不必销毁旧的对象。

编辑:当这是在预分配的内存块上调用任何构造函数的正确方法时,我不明白为什么要投票。这是msvc++ Allocator::construct函数,它做同样的事情

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

也想贬低msvc++的声誉吗?

你只需要使用位置new。

顺便说一句,你使用析构函数是没问题的:

// destruct all old elements
std::for_each(mBegin, mEnd, [](T& item) { item.~T(); });
表达式item.~T();是显式调用析构函数的正确方法。

不能这样调用构造函数

因此,位置new可以是一种方法:

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

顺便说一句,当在成员函数中使用lambdas时,您可能需要将this传递到捕获列表中。

为什么析构函数可以工作,而构造函数不行?

因为析构函数属于实例而构造函数属于类型。

不能使用实例来调用构造函数,必须使用类型的name来调用它。无论如何,你做了一些奇怪的事情。