是在指针的映射中定义的行为的默认值nullptr吗? [英] Is a default value of nullptr in a map of pointers defined behaviour?
问题描述
以下代码似乎总是遵循真正的分支。
#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 beO(n)
instead ofO(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 typeLog*
to referencenullptr
by default thus making the lookup checkO(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 tonullptr
.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屋!