我有这样的代码:
class MapIndex
{
private:
typedef std::map<std::string, MapIndex*> Container;
Container mapM;
public:
void add(std::list<std::string>& values)
{
if (values.empty()) // sanity check
return;
std::string s(*(values.begin()));
values.erase(values.begin());
if (values.empty())
return;
MapIndex *mi = mapM[s]; // <- question about this line
if (!mi)
mi = new MapIndex();
mi->add(values);
}
}
我主要担心的是,如果将新项添加到地图中,mapM [s]表达式是否会返回对NULL指针的引用?
SGI docs说: data_type&amp; operator [](const key_type&amp; k) 返回对与特定键关联的对象的引用。如果地图尚未包含此类对象,则operator []会插入默认对象data_type()。
所以,我的问题是默认对象data_type()的插入是否会创建一个NULL指针,或者它是否会创建指向内存中某处的无效指针?
答案 0 :(得分:22)
它会创建一个NULL
(0)指针,无论如何都是无效指针:)
答案 1 :(得分:18)
是的,它应该是一个零(NULL)指针,因为stl容器将默认初始化对象(如果没有显式存储)(即在执行时访问地图中不存在的键或将矢量调整为更大的尺寸) )。
C ++标准,8.5第5段规定:
默认初始化一个对象 类型T表示:
- 如果T是非POD类类型(子类),则为默认值 调用T的构造函数(和 如果T有,则初始化是不正确的 没有可访问的默认构造函数)
- 如果T是数组类型,则每个元素都是默认初始化的
- 否则,对象的存储空间被初始化。
您还应该注意,默认初始化与简单地省略构造函数不同。省略构造函数并简单地声明一个简单类型时,您将获得一个不确定的值。
int a; // not default constructed, will have random data
int b = int(); // will be initialised to zero
答案 2 :(得分:3)
更新:我完成了我的程序,我要问的那条线有时会导致它崩溃,但是在稍后阶段。问题是我正在创建一个新对象而不更改存储在std :: map中的指针。真正需要的是引用或指向该指针的指针。
MapIndex *mi = mapM[s]; // <- question about this line
if (!mi)
mi = new MapIndex();
mi->add(values);
应更改为:
MapIndex* &mi = mapM[s]; // <- question about this line
if (!mi)
mi = new MapIndex();
mi->add(values);
我很惊讶没有人注意到这一点。
答案 3 :(得分:2)
表达式data_type()
计算为默认初始化对象。在非POD类型的情况下,调用默认构造函数,但是在POD类型的情况下,例如指针,默认初始化相当于零初始化。
所以是的,您可以依靠地图创建NULL
指针。有关说明,请参阅Pseudo Constructor Initializers。
答案 4 :(得分:0)
不确定崩溃,但定义内存泄漏如此声明
if(!mi) mi = new MapIndex();
总是返回true,因为指针mi不是对mapM所持有的引用 对于s的特殊价值。
我也会避免使用常规指针并使用boost :: shared_ptr或其他 其他指针在销毁时释放内存。这允许调用mapM.clear()或erase() 应调用存储在地图中的键和值的析构函数。好吧,如果值是POD,例如指针,那么除非手动删除,否则不会为其调用析构函数 迭代整个地图会导致内存泄漏。