我正在学习C ++并阅读C ++ Primer。有一个问题我想知道答案:
给定指针 p ,您能否确定 p 是否指向有效对象?如果是这样,怎么样?如果没有,为什么不呢?
感谢。
答案 0 :(得分:35)
并且你想要检查一个指针是否有效,因为你知道指针来自哪里,因为它是你代码的私有部分你控制,或者因为你在面向外部的合同中指定了它。
答案 1 :(得分:11)
不可能。想想这种情况。
int *ptr = new int(10);
int *ptrDup = ptr;
delete ptr;
但ptrDup
仍然指向ptr
指向的内存位置,该位置不再存在。因此,引用ptrDup
会导致未定义的行为。但是引用计数是完全不同的概念。
答案 2 :(得分:6)
无法确定指针是否在所有含义中都是“有效”。
当然,您可以尝试取消引用指针(*ptr = x;
或x = *ptr
)。如果您的代码没有崩溃,则指针指向有效内存。如果它崩溃了,显然,指针是不好的。不幸的是,这种方法有点像检查枪是否被装在头上 - 这不是最聪明的......不幸的是,有了指针,没有“检查腔室是否装满”,所以没有真正好的方法来确定指针是否有效,除了“如果它不会导致硬件故障,它是有效的”。
请注意,在大多数情况下,这只会告诉您“指针指向您可以访问的某些内存”。这并不意味着指针“对于你想要的是正确的”(例如,它指向正确的类型)。并且它只是不会告诉你指针是否指向“陈旧数据”(也就是说,当指针WAS有效时,但它现在用于其他东西的内存)。
不幸的是,在现代系统中,2 32 或2 64 [实际上2 48 ]可能是有效的内存地址,几乎不可能知道哪些地址有效,哪些地址不有效。即使在操作系统内部,操作系统如果能够写入您要求它写入的内存,也会“尝试写入,看看会发生什么”。对于操作系统,这很好,因为它可以小心“这可能会出错,如果确实如此,我将继续在那里的错误恢复代码”。操作系统必须处理这个问题,因为它必须接受,a)程序员犯错误,以及b)有些人实际上将恶意代码写入TRY以破坏操作系统。
应用程序“确保指针有效”的方式是程序员编写关于它在指针中存储的内容的代码,如何释放这些指针,以及仅使用存储在其中的有效值的指针。你最终不应该“检查指针是否有效” - 然后你“做错了”。
(当你使用系统一段时间,并在调试器中读取指针值时,你会在一段时间后识别出“好”和“坏”指针 - 但这只是因为你通常会学到一个好的指针编写错误的指针看起来就好了。写代码来识别这种情况几乎是不可能的 - 特别是如果系统分配了大量内存,那么它会使用大部分可用空间。)
当然,在C ++中,有智能指针,向量和各种其他工具,这意味着很多时候你甚至不用打扰指针。但是理解如何使用指针以及指针如何工作仍然是一件好事。
答案 3 :(得分:4)
如果指针设置为nullptr
,则表示尚未给出指向的对象,而是指定了“默认”值。指针可能不分配给nullptr
和,同时不会分配给有效对象,但在这种情况下,这将是不可能的确定。例如:
使用nullptr
:
int *ptr = nullptr;
// check if pointer is unassigned to an object
if (ptr == nullptr) ptr = new int{0};
没有nullptr
:
int *ptr;
// using ptr while uninitialized is Undefined Behavior!
if (ptr != &some_object)
答案 4 :(得分:1)
如其他答案中所述,使用pip install --user ffmpeg-python
形式的原始指针无法做到这一点。但是,SomeObject* somePointer
引入了一组新的dynamic memory management and new smart pointers。使用智能指针可以检测资源是否仍然可用。例如,如下所示:
c++11
有关更多示例,请详细了解std::shared_ptr和std::weak_ptr。在boost
中提供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.
种等效智能指针之前。
答案 5 :(得分:-1)
C ++规范不提供任何支持来确定指针是否有效。最好是使用智能指针,因为您不太可能滥用它们(它们有各种各样的防护措施,可以进行适当的操作)。
但是,许多公司开发了库和工具来添加代码以检查每个内存访问,如果其中一个无效,则会出现中断。
对于g ++,我使用sanitizer选项如下:
g++ -fsanitize=address -fsanitize=enum -fsanitize=unreachable ...
第一个将保护您的内存访问,以至于SEGV会检测到尝试使用错误的指针。它使用MMU保护您的内存,因此它是由硬件驱动的。它会使您的代码变慢,但是仍然非常快。在这种模式下需要注意的一件事是,二进制文件分配了2Tb的虚拟内存。除非您有大量RAM,否则您不想同时运行太多这样的二进制文件。
请注意:部分代码来自Google,第一个实现是在clang中实现的。
在Linux下的直接C / C ++中,您可以测试指针是否在进程中。但是,有了大内存支持,这将失败,并且您也必须考虑堆栈。起始指针类似于0x400000。堆的结束地址可以使用sbrk()
确定。因此,您的堆指针应该在这两个边界之间。