两个指针指向同一内存位置并删除其中一个
Two pointers pointing to same memory location and deleting one of those
我在两个不同的线程中有两个不同类访问指向另一个类的指针。在第一个线程中,这个指针根据一些用户输入被删除,而secodn线程仍然试图访问那个内存位置,此时应用程序崩溃。两个线程之间共享的所有数据结构都受到所需锁的保护,并且不存在竞争条件。我在这里省略了与锁等相关的细节。
威胁1:
class UD
{
public:
char* GetName(); //returns name of UD entry
private:
//some data
char* name;
}
struct UDentry
{
class UD* mpUd;
//and other required member variables
};
class ABC
{
--usual functions
UD* getUD(const char* name);
private:
std::vector<struct UDentry> mUDs;
};
UD* ABC::getUD(const char* name)
{
if((idx = GetIndex(name)) >= 0)
{
return(mUDs[idx].mpUd);
}
else
{
// o/w create UD and return it
//............... Create UD, say localUd
//and add it to mUDs
if((idx = GetIndex(pFontName)) >= 0)
{
return(mUDs[idx].mpUd);
}
}
}
//有一些代码可以确保只有一个具有给定名称的UD被添加到列表中。我现在无法更改数据结构,尽管我知道它不是正确的数据结构。
int ABC::GetIndex(const char * pName) const
{
for(int i = 0; i < mUDs.size(); ++i)
{
if((stricmp(mUDs[i].mpUd->GetName(), pName) == 0))
return i;
}
return(-1);
}
//在另一个线程中,有一个名为DrawList的列表。//它包含指向UD的指针,并使用它,并根据UD 中的信息在屏幕上绘制一些内容
线程2:
class Item
{
public:
Item(char* name, //other args);
private:
UD* mpUd;
}
Item::Item(char* name, //other args):
mpUd(getUD(name))
{
}
//Stores draw commands
class DrawList
{
public:
DrawList();
~DrawList();
void AddItem(Item *pItem);
//method to draw text on screen based on info in UD
void Draw();
private:
DrawList * mpHead; //!< Pointer to the start of the list of blocks containing rendering commands (or NULL if empty)
DrawList * mpTail; //!< Pointer to the last addtion to the list of block of rendering commands (for easy & fast apends)
//and some other class specific methods and variables
};
class Render
{
private:
//contains a ptr to DrawList class, another boost::shared_ptr to Drawlist and a mutex to access list
//This class sits in a tight loop,
}
void DrawList::Draw()
{
//takes each item in turn and displays some text on-screen based on info in UD
}
所有这些都是遗留代码,所以我不能选择将ptr更改为智能ptr等,庞大的代码库
我为这个代码添加了一些新功能。现在,在创建UD的第一个线程中,根据一些用户操作,我们可能不得不删除UD
//new methods
bool ABC::deleteUD()
{
if((idx = GetIndex(pFontName)) >= 0)
{
delete mUDs[idx].mpUd;
mUDs[idx].mpUd = 0;
return true;
}
return false;
}
//现在,在第二个线程中,这个UD已经被多次添加到Drawlist中,并且一些绘制节点仍然有一个指向那个UD的ptr。//UD上的所有这些删除、添加和呈现都是通过互斥锁保护完成的,因此不存在竞争条件。
我曾假设,如果我删除了ABC类中的UD并使其为Null,那么指针(项目::mpUd(也将变为Null。但那个指针仍然指向那个地址,那个地址空间的内存要么被重新使用,要么包含垃圾值(这很令人惊讶,因为我以为我把它设为Null(。所以,当在Draw方法中,我试图访问它时,程序崩溃了。
在Draw中,在渲染之前,我正在检查,if(项目::mpUd(///这永远不是0{mpUd->GetName((//等,访问其方法。我撞车了}
我看过一个类似问题的答案:当有两个指针指向相同的内存位置时,C++删除一个指针
所以,我知道我所做的是错误的。任何建议,我如何正确地实现这种行为,我强调,我不能更改为共享ptrs
shared_ptr为您提供的是引用计数。所以你创建了一个shared_ptr,然后复制它来创建另一个,并通过这些访问你的内存。删除shared_ptr时,析构函数不会释放内存。只有当最后一个shared_ptr被销毁时,它才会执行此操作。
如果你(以某种方式(设法让两个独立的shared_ptr指向同一内存,shared_ptrs对你没有帮助,但这永远不会发生,你对指针的内存有很强的所有权(你不应该把它看作普通的C指针,而应该把它更多地看作shared_ptr对象的内容,就像任何其他对象包含数据一样(。
因此,您可以在外部实现同样的行为。每次初始化指向共享内存区域的指针时,都会增加一个引用计数器。每次"释放"它时,都会递减引用计数器。当引用计数器递减到0时,然后,也只有这样,才能释放内存。
如果没有垃圾收集器,就由程序员来管理对象的生存期。有一些模式可以让这项工作变得更容易,而智能指针可以让实现其中一些模式变得更容易。
您目前有两个对象,我们将它们称为A
和B
,而B
负责delete
—在A
中执行某些操作A
的某些对A
的所有生存期都有效,但A
的某些受B
的生存期限制。今天,这被认为是一个坏主意,而且几乎不可能把它做好。人们普遍认为,让B
了解A
的内部总是一个坏主意(德米特定律(,虽然我认为这是一个很好的经验法则,但你不必重新设计所有东西来遵循它
对于你现在遇到的问题,最好的答案是简单地停止一个对象delete
——另一个对象内部的东西。让每个对象负责管理其内部的生命周期。从您发布的代码来看,B
没有理由仅仅因为不想再使用指针而调用delete
。相反,您可以将B
NULL
从指针的副本中取出,同时保留原始对象供其他对象(例如C
(使用。正如您所了解的,NULL
使用一个指针不会影响其他指向同一事物的指针:
int i = 5;
int* ip = &i;
int* ip2 = &i;
int* ip3 = ip;
int* ip4 = ip2;
ip = NULL; // has no effect on ip2, ip3 or ip4
- 删除一个线程上有数百万个字符串的大型哈希映射会影响另一个线程的性能
- 从链接列表c++中删除一个项目
- G++ 发出警告,要求删除一个代码的数组,但不删除另一个代码的数组
- 除了调用全局删除运算符之外,删除一个void指针还能做什么呢
- 仅从无序集合中删除一个项目
- C++ 从数组中删除一个最大值和零
- 如果一个类继承了一个带有虚拟 dtor 的类,为什么要删除一个没有虚拟 dtor 的类是可以的
- 如何在不使用循环或迭代器的情况下检查所有列表元素并在满足条件时删除一个
- 我只想从文本文件中删除一个特定值或行
- C 对象阵列删除一个
- 在包含相同项目的向量中删除一个项目
- 当Ccarray_foreach中删除一个对象时,就会发生问题
- 从C++二进制搜索树中删除一个节点(类而非结构)
- C 从整数删除一个数字
- 如何从C 中的对象向量中删除一个项目
- 在单个链接列表中间删除一个节点,仅给定对该节点的访问
- 很难从我的二进制搜索树中删除一个节点
- 添加两个节点并在比较时删除一个节点
- C++-从单链循环列表中的任何索引中删除一个节点
- 如何从结构数组中删除一个数据行?(带索引)