是在指针的映射中定义的行为的默认值nullptr吗? [英] Is a default value of nullptr in a map of pointers defined behaviour?

查看:202
本文介绍了是在指针的映射中定义的行为的默认值nullptr吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

以下代码似乎总是遵循真正的分支。

  #include< map> 
#include< iostream>

class TestClass {
// implementation
}

int main(){
std :: map< int,TestClass *> ; TestMap;
if(TestMap [203] == nullptr){
std :: cout<< 真正;
} else {
std :: cout<< 假;
}
return 0;
}

它是一个未初始化指针的行为,指向 nullptr 或者我的编译器的工件?



如果不是,我如何保证下面代码的可移植性?目前,我使用类似的逻辑为日志文件返回正确的单例实例:

  #include< string> 
#include< map>

class Log {
public:
static Log * get_instance(std :: string path);
protected:
Log(std :: string path):path(path),log(path){};
std :: string path;
std :: ostream log;
private:
static std :: map< std :: string,Log *>实例;
};

std :: map< std :: string,Log *> Log :: instances = std :: map< std :: string,Log *>();

日志* Log :: get_instance(std :: string path){
if(instances [path] == nullptr){
instances [path] = new Log );
}
return instances [path];
}

一个解决方案是使用类似于这里的东西,当你使用一个特殊的函数检查 map 时提供一个默认值。但是,我的理解是,这将导致查找的复杂度 O(n)而不是 O(1)。这在我的场景中不是太多的问题(只会有少量日志),但更好的解决方案将以某种方式强制类型 Log * 在默认情况下引用 nullptr ,从而使查找检查 O(1)和便携式同时。

解决方案

地图总是对其成员进行初始化(在这种情况下它们不是复制初始化的,当然),并且内置类型的值初始化意味着零初始化,因此它确实是定义的行为。对于在访问 operator [] 的元素时生成的新键的值部分尤其如此。



注意,一个未初始化的指针不是必须是一个空指针;实际上,只是读取其值已经调用未定义的行为(并且可能在某些情况下在某些平台上的分段错误)。关键是地图中的指针不是未初始化的。所以如果你写例如

  void foo()
{
TestClass * p;
// ...
}

p c



注意

不会被初始化为 nullptr 但是您可能希望检查是否存在,以避免累积不必要的条目。您可以使用 find 成员函数检查是否存在:

  map< ; int,TestClass *> :: iterator it = TestMap.find(203); 
if(it == map.end())
{
//在地图中没有这样的元素
}
else
{
TestClass * p = it-> second;
// ...
}


The following code seems to always follow the true branch.

#include <map>
#include <iostream>

class TestClass {
  // implementation 
}

int main() {
  std::map<int, TestClass*> TestMap;
  if (TestMap[203] == nullptr) {
    std::cout << "true";
  } else {
    std::cout << "false";
  }
  return 0;
}

Is it defined behaviour for an uninitialized pointer to point at nullptr, or an artifact of my compiler?

If not, how can I ensure portability of the following code? Currently, I'm using similar logic to return the correct singleton instance for a log file:

#include <string>
#include <map>    

class Log {
  public:
    static Log* get_instance(std::string path);
  protected:
    Log(std::string path) : path(path), log(path) {};
    std::string path;
    std::ostream log;
  private:
    static std::map<std::string, Log*> instances;
};

std::map<std::string, Log*> Log::instances = std::map<std::string, Log*>();

Log* Log::get_instance(std::string path) {
  if (instances[path] == nullptr) {
    instances[path] = new Log(path);
  }
  return instances[path];
}

One solution would be to use something similar to this where you use a special function provide a default value when checking a map. However, my understanding is that this would cause the complexity of the lookup to be O(n) instead of O(1). This isn't too much of an issue in my scenario (there would only ever be a handful of logs), but a better solution would be somehow to force pointers of type Log* to reference nullptr by default thus making the lookup check O(1) and portable at the same time. Is this possible and if so, how would I do it?

解决方案

The map always value-initializes its members (in situations where they are not copy-initialized, of course), and value-initialization for builtin types means zero-initialization, therefore it is indeed defined behaviour. This is especially true for the value part of new keys generated when accessing elements with operator[] which didn't exist before calling that.

Note however that an uninizialized pointer is not necessarily a null pointer; indeed, just reading its value already invokes undefined behaviour (and might case a segmentation fault on certain platforms under certain circumstances). The point is that pointers in maps are not uninitialized. So if you write for example

void foo()
{
  TestClass* p;
  // ...
}

p will not be initialized to nullptr.

Note however that you might want to check for presence instead, to avoid accumulating unnecessary entries. You'd check for presence using the find member function:

map<int, TestClass*>::iterator it = TestMap.find(203);
if (it == map.end())
{
  // there's no such element in the map
}
else
{
  TestClass* p = it->second;
  // ...
}

这篇关于是在指针的映射中定义的行为的默认值nullptr吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆