Bob*_*bby 11 c++ containers undefined-behavior
以下代码
#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;
}
Run Code Online (Sandbox Code Playgroud)
在没有警告的情况下编译(g ++),执行时没有错误,并且通过输出判断kill
方法foo
从地图中删除对象.但是,我觉得这可能实际上是未定义的行为.似乎kill
在行之后的行m.erase(i)
this
不再指向有效对象.
C++标准对此有何看法?
当您输入时kill
,m[1]
(from m[1].kill(m, 1);
)语句已被完全评估为foo
您正在调用的对象kill
.
然后你m.erase(i);
最终破坏了当前的对象foo
.
至于this
在从kill
函数返回之前绝对没有使用当前对象()编写语句,这是完全可以接受和安全的(由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;
};
Run Code Online (Sandbox Code Playgroud)
所以,让我们说你正在做的事情是有风险的,但如果你做得好,那就是有效和安全的.
作为一个例子,这将最终定义行为并且可以完成:
struct foo
{
void kill(std::map<int, foo>& m, int i)
{
int theAttribute = attribute;
m.erase(i);
cout << theAttribute; // OK!
}
int attribute;
};
Run Code Online (Sandbox Code Playgroud)
有一个方法删除当前对象可能不是一个好的做法(特别是如果另一个开发人员稍后修改代码......他可以很容易地使它崩溃与上面的第一个例子).至少在代码中放置一个明确的注释来告诉当前对象可能已经被销毁(注意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!
}
};
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
269 次 |
最近记录: |