C++ 是否可以确定指针是否指向有效对象?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/17202570/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-27 21:00:06  来源:igfitidea点击:

C++ Is it possible to determine whether a pointer points to a valid object?

c++pointers

提问by 2013Asker

I'm learning C++ and reading C++ Primer. There's a question I would like to know the answer:

我正在学习 C++ 并阅读 C++ Primer。有个问题想知道答案:

Given a pointer p, can you determine whether ppoints to a valid object? If so, how? If not, why not?

给定一个指针p,你能确定p是否指向一个有效的对象吗?如果是这样,如何?如果没有,为什么不呢?

回答by Kerrek SB

No, you can't. Why? Because it would be expensive to maintain meta data about what constitutes a valid pointer and what doesn't, and in C++ you don't pay for what you don't want.

不,你不能。为什么?因为维护关于什么构成有效指针和什么无效的元数据会很昂贵,而且在 C++ 中,您不需要为不想要的东西付费。

And you don't wantto check whether a pointer is valid, because you knowwhere a pointer comes from, either because it's a private part of your code that you control, or because you specified it in your external-facing contracts.

并且您不想检查指针是否有效,因为您知道指针来自哪里,或者因为它是您控制的代码的私有部分,或者因为您在面向外部的合同中指定了它。

回答by Mahesh

Not possible. Think of this scenario.

不可能。想想这个场景。

int *ptr = new int(10);
int *ptrDup = ptr;

delete ptr;

But ptrDupstill points to the memory location pointed by ptrwhich no longer exists. So, deferencing ptrDupresults undefined behavior. But there is reference counting which is totally a different concept.

但是ptrDup仍然指向ptr不再存在的指向的内存位置。因此,推迟会ptrDup导致未定义的行为。但是引用计数是一个完全不同的概念。

回答by Mats Petersson

Not really possible to see if a pointer is "valid" in all it's meanings.

不太可能看到一个指针在所有含义中是否“有效”。

Sure, you can try to dereference the pointer (*ptr = x;or x = *ptr). If your code didn't crash, the pointer is pointing to valid memory. If it crashed, obviously, the pointer is no good. Unfortunately, this approach is a bit like checking if a gun is loaded by firing it at your head - which isn't the cleverest... Unfortunately, with pointers, there is no "check the chamber to see if it's loaded", so no real good way to figure out if the a pointer is valid, other than "if it doesn't cause an hardware fault, it's valid".

当然,您可以尝试取消引用指针 (*ptr = x;x = *ptr)。如果您的代码没有崩溃,则指针指向有效内存。如果它崩溃了,显然,指针是没有用的。不幸的是,这种方法有点像通过向您的头部开火来检查枪是否已装弹 - 这不是最聪明的...除了“如果它不会导致硬件故障,它是有效的”之外,没有真正的好方法来确定 a 指针是否有效。

Note that this will only really tell you that "the pointer is pointing at some memory you can access" in most cases. It does NOT mean that the pointer "is correct for what you want it to be" (e.g. it points to the correct type). And it CERTAINLY won't tell you if the pointer is pointing to "stale data" (that is, when a pointer WAS valid, but it's now memory used for something else).

请注意,在大多数情况下,这只会真正告诉您“指针指向您可以访问的某些内存”。这并不意味着指针“对于您想要的内容是正确的”(例如,它指向正确的类型)。它肯定不会告诉您指针是否指向“陈旧数据”(即,当指针有效时,但它现在是用于其他用途的内存)。

Unfortunately, with 232or 264[actually 248] possibly valid memory addresses in a modern system, it's almost impossible to know what addresses are valid and which ones are not. Even inside the operating system, the way the OS figures out if it can write to the memory you asked it to write to is "try to write it, see what happens". For the OS, this works out fine, because it can be careful about "this may go wrong, and if it does, I'll continue over there in the error recovery code". The OS has to deal with this because it has to accept, a) that programmers make mistakes, and b) that some people actually write malicious code to TRY to break the OS.

不幸的是,在现代系统中,2 32或 2 64[实际上是 2 48] 可能是有效的内存地址,几乎不可能知道哪些地址有效,哪些无效。即使在操作系统内部,操作系统确定它是否可以写入您要求它写入的内存的方法是“尝试写入它,看看会发生什么”。对于操作系统,这很有效,因为它可以小心“这可能会出错,如果出错,我将继续在错误恢复代码中”。操作系统必须处理这个问题,因为它必须接受:a) 程序员会犯错误,以及 b) 有些人实际上编写了恶意代码来尝试破坏操作系统。

The way for an application to "make sure pointers are valid" is that the programmer writes code that is CAREFUL about what it stores in pointers, how it frees those pointers, and only use pointers that have valid values stored in them. You shouldn't end up "having to check whether the pointer is valid" - then you are "doing it wrong".

应用程序“确保指针有效”的方法是程序员编写代码,注意它在指针中存储的内容,如何释放这些指针,并且只使用其中存储了有效值的指针。你不应该最终“必须检查指针是否有效”——那么你就是“做错了”。

(When you work with a system for a while, and reading pointer values in a debugger, you do after a while recognise "good" and "bad" pointers - but that's just because you learn what, usually, a good pointer vs. a bad pointer looks like. To write code to recognise such is almost impossible - especially if the system is allocating a lot of memory, so it uses most of the available space.)

(当您使用系统一段时间并在调试器中读取指针值时,您会在一段时间后识别“好”和“坏”指针 - 但这只是因为您通常了解什么是好指针与坏指针看起来像。编写代码来识别这种情况几乎是不可能的 - 特别是如果系统分配了大量内存,因此它使用了大部分可用空间。)

Of course, in C++, there are smart pointers, vectors, and various other tools that mean a lot of the time you don't even have to bother with pointers. But understanding how to use pointers and how pointers work is still a good thing to do.

当然,在 C++ 中,有智能指针、向量和各种其他工具,这意味着很多时候您甚至不必为指针烦恼。但是了解如何使用指针以及指针如何工作仍然是一件好事。

回答by 0x499602D2

If a pointer is set to nullptr, that means it hasn't been given an object to point to and instead has been given a "default" value. It's possible that the pointer could notbe assigned to nullptrandat the same time not be assigned to a valid object, but in that case it would be impossible to determine that. For example:

如果指针设置为nullptr,则意味着它没有被赋予指向的对象,而是被赋予了“默认”值。这有可能是指针也不会被分配到nullptr在同一时间不能分配给一个有效的对象,但在这种情况下,将无法确定。例如:

With nullptr:

nullptr

int *ptr = nullptr;

// check if pointer is unassigned to an object
if (ptr == nullptr) ptr = new int{0};

Without nullptr:

没有nullptr

int *ptr;

// using ptr while uninitialized is Undefined Behavior!
if (ptr != &some_object)

回答by Fantastic Mr Fox

As stated in other answers, this is not possible with a raw pointer of the form SomeObject* somePointer. However, c++11introduced a new set of dynamic memory management and new smart pointers. Using a smart pointer you can detect if the resource is still available. For example in the following:

正如其他答案中所述,使用 形式的原始指针是不可能的SomeObject* somePointer。但是,c++11引入了一组新的动态内存管理和新的智能指针。使用智能指针,您可以检测资源是否仍然可用。例如在下面:

std::weak_ptr<int> w; // Our pointer to a resource.
{
    std::shared_pointer<int> s = std::make_shared<int>(5); // The resource.

    w = s;       // We can set the weak pointer to the shared pointer.

    auto s2 = w; // Here we can promote the weak pointer to a shared  pointer to control 
                 // the resource.

    *s2 = 6;     // Here we can use the resource.

}                // Here the resource is destroyed.

auto s2 = w;     // Here we will fail to get the resource because it has been destroyed. We
                 // have successfully used smart pointers to detect if the resource exists.

Read more about std::shared_ptrand std::weak_ptrfor more examples. Before c++11equivelent types of smart pointers are available in boost.

阅读更多关于std::shared_ptrstd::weak_ptr的更多示例。之前c++11equivelent类型的智能指针都可用boost

回答by Alexis Wilke

The C++ specification does not give us any kind of support to determine whether a pointer is valid. The best is to use smart pointers because you are much less likely to misuse them (they have various guards allowing proper manipulation).

C++ 规范没有给我们任何类型的支持来确定指针是否有效。最好的方法是使用智能指针,因为您不太可能误用它们(它们有各种保护措施可以进行适当的操作)。

However, various companies develop libraries and tools to add code to check eachmemory access and if one is invalid, you get an interrupt.

然而,许多公司开发了库和工具来添加代码来检查每个内存访问,如果一个无效,你会得到一个中断。

With g++, I use the sanitizeroptions like so:

使用 g++,我使用消毒剂选项,如下所示:

g++ -fsanitize=address -fsanitize=enum -fsanitize=unreachable ...

The first one will protect your memory accesses to a point where trying to use the wrong pointer is going to be detected with a SEGV. It uses the MMU to protect your memory so it's hardware driven. It slows down your code, but it still pretty fast. One thing to watch out for in this mode, the binaries allocate 2Tb of virtual memory. You don't want to run too many such binaries simultaneously unless you have a lot of RAM.

第一个将保护您的内存访问到尝试使用错误指针将被 SEGV 检测到的点。它使用 MMU 来保护您的内存,因此它是由硬件驱动的。它减慢了你的代码,但它仍然相当快。在这种模式下需要注意的一件事是,二进制文件分配了 2Tb 的虚拟内存。除非您有大量 RAM,否则您不想同时运行太多此类二进制文件。

As a side note: part of the code comes from Google and the first implementation was in clang.

附带说明:部分代码来自 Google,第一个实现是在 clang 中。

In direct C/C++ under Linux, you can test whether a pointer is within your process. However, with large memory support, that will fail and you have to take the stack in account too. The start pointer is something like 0x400000. The end address of the heap can be determined using sbrk(). So your heap pointers should be between those two boundaries.

在Linux下的直接C/C++中,你可以测试一个指针是否在你的进程内。但是,对于大内存支持,这将失败,您也必须考虑堆栈。起始指针类似于 0x400000。可以使用 确定堆的结束地址sbrk()。所以你的堆指针应该在这两个边界之间。