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

时间:2015-09-07 15:08:12

标签: c++ c++11 stl

我在使用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()?为什么析构函数可以工作而不是构造函数?

4 个答案:

答案 0 :(得分:5)

您可以使用std::uninitialized_copy()

答案 1 :(得分:0)

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

::operator new(ptr) T(item)

item应作为const引用传递。 (或更好 - 移动)

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

您还应移动对象,而不是复制和删除旧对象。 这也将使你免于破坏旧物体的需要。

编辑: 当这是在预先分配的内存块上调用任何构造函数的正确方法时,我不明白为什么downvote。这是MSVC ++ Allocator::construct函数,它执行相同的操作

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

是否也希望获得MSVC ++的声誉?

答案 2 :(得分:0)

您只需使用展示位置。

btw你使用析构函数是好的:

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

表达式item.~T();是显式调用析构函数的正确方法。

你不能以这种方式调用构造函数。

所以,放置新的可能是要走的路:

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

btw在成员函数中使用lambdas时,您可能需要将this传递到捕获列表中。

答案 3 :(得分:0)

  

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

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

您无法调用具有该实例的构造函数,您必须使用该类型的名称来调用它。无论如何,你做的事情很奇怪。