gpt4 book ai didi

c++ - 从成员类调用封装的 std::begin 时程序崩溃

转载 作者:行者123 更新时间:2023-11-28 01:31:33 26 4
gpt4 key购买 nike

我的生产代码崩溃了,我找不到原因,所以我寻找罪恶的根源,现在成功地构建了一个最小的示例,其中变体 B 重现了错误。

也许有人可以帮助我了解这里的问题是什么?

为什么变体 B 会崩溃而变体 A 不会?对我来说,这两种变体似乎应该具有相同的行为?

visual studio 2017 调试器的输出:

void _Adopt(const _Container_base12 *_Parent) _NOEXCEPT
{ // adopt this iterator by parent
if (_Parent == 0)
{ // no future parent, just disown current parent
#if _ITERATOR_DEBUG_LEVEL == 2
_Lockit _Lock(_LOCK_DEBUG);
_Orphan_me();
#endif /* _ITERATOR_DEBUG_LEVEL == 2 */
}
else
{ // have a parent, do adoption
_Container_proxy *_Parent_proxy = _Parent->_Myproxy;

#if _ITERATOR_DEBUG_LEVEL == 2
if (_Myproxy != _Parent_proxy)
{ // change parentage
_Lockit _Lock(_LOCK_DEBUG);
_Orphan_me();
_Mynextiter = _Parent_proxy->_Myfirstiter; <--- MARKED HERE
_Parent_proxy->_Myfirstiter = this;
_Myproxy = _Parent_proxy;
}

#else /* _ITERATOR_DEBUG_LEVEL == 2 */
_Myproxy = _Parent_proxy;
#endif /* _ITERATOR_DEBUG_LEVEL == 2 */
}
}

最小的可编译示例:

#include <vector>

using namespace std;

template <class T>
struct IteratorCapsule
{
const T * m_ptrObj;
IteratorCapsule(const T &refObj) : m_ptrObj(&refObj) {}
typename T::const_iterator begin() const { return std::begin(*m_ptrObj); }
typename T::const_iterator end() const { return std::end(*m_ptrObj); }
};

struct Element
{
vector<int> m_attr;
IteratorCapsule<vector<int>> m_attr_iter_capsule;

Element() : m_attr_iter_capsule(m_attr) {}

const IteratorCapsule<vector<int>> &getAttributes() const
{
return m_attr_iter_capsule;
}
};

struct Config
{
vector<Element> m_element_pool;
Config() { m_element_pool.push_back(Element()); }
};

int main()
{
//variant A
Config oConfigA;
IteratorCapsule<vector<int>> oIterCapsule(oConfigA.m_element_pool[0].m_attr);
auto iterBeginA = oIterCapsule.begin();

//variant B -> crash
Config oConfigB;
auto iterBeginB = oConfigB.m_element_pool[0].getAttributes().begin();

return 0;
}

最佳答案

让我们尝试显式实现 Element(Element&& x) 看看会发生什么。

Element(Element&& x) : m_attr (std::move(x.m_attr)),
m_attr_iter_capsule (std::move(x.m_attr_iter_capsule)) // WRONG
{}

当(但不仅限于)Element 从右值构造时调用,例如在这种情况下:

Element a {std::move(Element())};

在这种情况下,a.m_attr_iter_capsule 将包含指向内部 Element() 的指针(超出该行代码之后的范围)

(请注意,解除对越界指针的引用是未定义的行为。不保证它会发生段错误)

在OP的代码中,这一行

m_element_pool.push_back(Element());

调用 Element(Element&&)。使用 emplace_back() 可以“解决”这个问题(但这不是这个答案的重点)。

要修复它,只需定义明确的复制和移动构造函数,并适本地初始化m_attr_iter_capsule;或使用 = delete 删除这些构造函数。

关于c++ - 从成员类调用封装的 std::begin 时程序崩溃,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51340036/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com