对象是否可以从标准C++容器中擦除自身
Can an object erase itself from a standard C++ container?
以下代码
#include <iostream>
#include <map>
struct foo
{
void kill(std::map<int, foo>& m, int i)
{
m.erase(i);
}
};
int main()
{
std::map<int, foo> m;
m.emplace(1, foo() );
std::cout << m.size() << std::endl;
m[1].kill(m, 1);
std::cout << m.size() << std::endl;
}
编译而不发出警告 (G++(,执行时没有错误,并且从输出判断,kill
方法会从映射中删除foo
对象。但是,我觉得这实际上可能是未定义的行为。似乎在kill
方法中,行之后的m.erase(i)
this
不再指向有效对象。
C++标准对此有何规定?
当你输入你的kill
时,m[1]
(从m[1].kill(m, 1);
(语句已经被完全评估为你正在调用kill
的foo
对象。
然后你m.erase(i);
最终破坏当前对象foo
。
只要你在从kill
函数返回之前绝对不使用当前对象(this
(编写任何语句,这是完全可以接受和安全的(正如Auriga和Barry引用的帖子所评论的那样(。即使当前对象不再存在,您的函数也会从堆栈中安全返回,据我所知,它没有理由失败。
作为例证,这将最终导致未定义的行为,并且不得这样做:
struct foo
{
void kill(std::map<int, foo>& m, int i)
{
m.erase(i);
cout << attribute; // don't do that! current foo object does not exist anymore
}
int attribute;
};
因此,假设您正在做的事情是有风险的,但如果您做得好,则有效且安全。
作为说明,这将最终定义行为并且可以完成:
struct foo
{
void kill(std::map<int, foo>& m, int i)
{
int theAttribute = attribute;
m.erase(i);
cout << theAttribute; // OK!
}
int attribute;
};
无论如何,让方法删除当前对象可能不是一个好的做法(特别是如果另一个开发人员稍后修改代码......他可以很容易地用上面的第一个例子让它崩溃(。至少在代码中放置一个明确的注释,以告诉当前对象可能已被销毁(请注意,kill
可以销毁当前对象、另一个对象或没有......取决于m
内容和i
(:
struct foo
{
void kill(std::map<int, foo>& m, int i)
{
m.erase(i);
// careful! current object could have been destroyed by above statement and may not be valid anymore! Don't use it anymore!
}
};
这根本不安全。 如果多次调用,m.erase(i)
将避免尝试擦除同一对象,但如果多次调用m[1].kill(m, 1)
则为未定义的行为。为了稍微安全一点,m.at(1).kill(m, 1)
会抛出out_of_range
错误。
相关文章:
- 引用一个已擦除类型(void*)的指针
- 擦除while循环中迭代的元素
- 在运行时处理类型擦除的数据-如何不重新发明轮子
- C++擦除(如果存在)
- 在映射擦除c++期间执行循环的次数
- 为什么擦除方法会影响结束方法
- C++ 字符串类擦除成员函数的时空复杂性
- 类型擦除的std::function与虚拟函数调用的开销
- C++14 中unordered_map矢量和擦除删除成语的奇怪行为
- C++ 擦除函数中需要澄清
- 循环挂起迭代的 std::擦除 on std::list
- 擦除许多矢量元素,同时使用'auto'
- 如何擦除冗余输入?
- C++ STL 设置按值擦除
- 如何在C++中允许成员函数的自定义返回类型进行类型擦除?
- 为什么我的向量::擦除调用会抛出"vector subscript out of range"?
- 如何在写入文件时擦除最后一个逗号
- C++:std::ofstream 方法 open() 在第二次迭代时擦除打开的 ifstream 文件
- 双链表的擦除值函数,未知错误
- 如何编写用于多映射插入和擦除功能的 API?