且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

检查已删除的地图条目 - >撞车?

更新时间:2023-12-02 18:45:40

bo ******* @ wanadoo.nl 写道:
bo*******@wanadoo.nl wrote:
I我在我的代码中使用了STL地图。
我的应用程序有时会尝试从地图中删除两次。
这会导致我当前代码崩溃。问题可能是我检查是否有必要删除某些东西(第44行和第52行,如下面的代码)。


是。

在下面的代码中证明了问题,第65行将导致
分段错误。

1 #include< iostream>
2 #include< cstdlib>
3 #include< map>
4
5使用命名空间std;
6
7类MyClass
8 {
9 public:
10 MyClass(int);
11~MyClass();
12 void show();
13 private:
14 int nr_;
15};
16
17 MyClass :: MyClass(int nr):nr_(nr)
18 {
19 cout<< MyClass: &LT;&LT; nr_<< &QUOT;构造&QUOT; &LT;&LT; endl;
20}
21
22 MyClass :: ~MyClass()
23 {
24 cout<< MyClass: &LT;&LT; nr_<< &QUOT;自毁&QUOT; &LT;&LT; endl;
25}
26
27无效MyClass :: show()
28 {
29 cout<< 显示此MyClass: &LT;&LT; nr_<< endl;
30}
31
32 typedef map< int,MyClass *> RtdmCyclicTimerMap;
33
34 int main(void)
35 {/ / 36 RtdmCyclicTimerMap cyclicRtdmTimer_;
37 map< int,MyClass *> :: const_iterator cyclicRtdmIt;
38
39 //创建1& 2
40 cyclicRtdmTimer_ [1] = new MyClass(11);
41 cyclicRtdmTimer_ [2] = new MyClass(22);
42
43 //删除2 > 44 if(cyclicRtdmTimer_ [2]){
45删除cyclicRtdmTimer_ [2];
46 cyclicRtdmTimer_.erase(2);
47}否则{
48 cout<< ; 删除2失败 &LT;&LT;如果(cyclicRtdmTimer_ [2]){
53删除cyclicRtdmTimer_ [2];
54 cyclicRtdmTimer_.erase(2);
55}否则{
56 cout<< 删除2 [2]失败 &LT;&LT; endl;
57}
58
59 //显示地图 - >现在它会崩溃
60 cout<< endl<< 将显示地图条目 &LT;&LT;结束;
61 for

(cyclicRtdmIt = cyclicRtdmTimer_.begin(); cyclicRtdmI t!= cyclicRtdmTimer_.end(); ++ cyclicRtdmIt){
62 int tKey = cyclicRtdmIt- >第一;
63 MyClass * mcPtr = cyclicRtdmIt-> second;
64 cout<< map entry found:key =" &LT;&LT; tKey<< ",valP =" <<
mcPtr<< ",val =";
65 mcPtr-> show();
66}
67}
68

这是因为行52以某种方式将内部地图大小从1
增加到2个条目。


如果operator []找不到您要搜索的元素,则会创建

该元素。否则,第40行和第41行无法按照他们的方式工作。

由于你没有在第52行指定任何东西,价值可能是

不确定,不能与删除一起使用。

必须用迭代器完成吗?
I''m using an STL map in my code.
My application sometimes tries to delete things twice from the map.
This leads to a crash in my current code. The problem is probably the
way I check whether it is necessary to delete something (line 44 and 52
in below code).
Yes.
In the below code the problem is demonstrated, line 65 will cause a
segmentation fault.
1 #include <iostream>
2 #include <cstdlib>
3 #include <map>
4
5 using namespace std;
6
7 class MyClass
8 {
9 public:
10 MyClass(int);
11 ~MyClass();
12 void show();
13 private:
14 int nr_;
15 };
16
17 MyClass::MyClass(int nr) : nr_(nr)
18 {
19 cout << "MyClass: " << nr_ << " constructed" << endl;
20 }
21
22 MyClass::~MyClass()
23 {
24 cout << "MyClass: " << nr_ << " destructed" << endl;
25 }
26
27 void MyClass::show()
28 {
29 cout << "Show this MyClass: " << nr_ << endl;
30 }
31
32 typedef map<int, MyClass *> RtdmCyclicTimerMap;
33
34 int main(void)
35 {
36 RtdmCyclicTimerMap cyclicRtdmTimer_;
37 map<int, MyClass *>::const_iterator cyclicRtdmIt;
38
39 // create 1 & 2
40 cyclicRtdmTimer_[1] = new MyClass(11);
41 cyclicRtdmTimer_[2] = new MyClass(22);
42
43 // delete 2
44 if (cyclicRtdmTimer_[2]) {
45 delete cyclicRtdmTimer_[2];
46 cyclicRtdmTimer_.erase(2);
47 } else {
48 cout << "delete 2 failed" << endl;
49 }
50
51 // delete 2 AGAIN
52 if (cyclicRtdmTimer_[2]) {
53 delete cyclicRtdmTimer_[2];
54 cyclicRtdmTimer_.erase(2);
55 } else {
56 cout << "delete 2[2] failed" << endl;
57 }
58
59 // show map -> NOW IT WILL CRASH
60 cout << endl << "going to show map entries" << endl;
61 for
(cyclicRtdmIt=cyclicRtdmTimer_.begin();cyclicRtdmI t!=cyclicRtdmTimer_.end(); ++cyclicRtdmIt) {
62 int tKey = cyclicRtdmIt->first;
63 MyClass *mcPtr = cyclicRtdmIt->second;
64 cout << "map entry found: key=" << tKey << ", valP=" <<
mcPtr << ", val=";
65 mcPtr->show();
66 }
67 }
68
This is because line 52 somehow increases the internal map size from 1
to 2 entries.
If operator[] doesn''t find the element you are searching for, it creates
that element. Otherwise, line 40 and 41 couldn''t work the way they do.
Since you don''t assign anything to it in line 52, the value is probably
indeterminate and cannot be used with delete.
Must it be done with an iterator ?




是的。使用find()成员函数而不是operator []。这绝不会是b $ b创建元素。如果找到元素,你会得到一个迭代器,

否则你得到结束()。



Yes. Use the find() member function instead of operator[]. This will never
create elements. If the element is found, you get an iterator to it,
otherwise you get end().


> 51 //删除2 AGAIN
> 51 // delete 2 AGAIN
52 if(cyclicRtdmTimer_ [2]){
52 if (cyclicRtdmTimer_[2]) {




问题出在这里。这隐式地向地图添加了一个元素,并且
用NULL初始化指针。当您尝试取消引用该指针

之后,您会遇到段错误。


您可以使用以下检查:

if(cyclicRtdmTimer_.find(2)!= cyclicRtdmTimer_.end()){


祝福,

-

Andrei Tarassov

软件工程师

Altiris,Inc。
www.altiris.com



The problem is here. This implicitly adds an element to the map and
initializes the pointer with NULL. When you try to dereference that pointer
later, you get a segfault.

You could use the following check instead:
if (cyclicRtdmTimer_.find(2) != cyclicRtdmTimer_.end()) {

Best wishes,
--
Andrei Tarassov
software engineer
Altiris, Inc.
www.altiris.com


Rolf Magnus写道:
Rolf Magnus wrote:
如果是运算符[]找不到你要搜索的元素,它创建了那个元素。否则,第40行和第41行无法按照他们的方式工作。
由于你没有在第52行中为它指定任何内容,因此该值可能是不确定的,不能与删除一起使用。
If operator[] doesn''t find the element you are searching for, it creates
that element. Otherwise, line 40 and 41 couldn''t work the way they do.
Since you don''t assign anything to it in line 52, the value is probably
indeterminate and cannot be used with delete.




好​​的,别忘了。安德烈是对的。新添加的指针被初始化为
一个空指针,因为如果它不是空指针你只删除它,它就会停留在你的地图中。之后,当您尝试取消引用它时,您的程序

崩溃。



Ok, forget that. Andrei is right. The newly added pointer is initialized to
a null pointer, and since you only remove it if it''s not a null pointer, it
stays in your map. Later, when you try to dereference it, your program
crashes.