Dmi*_*try 5 c++ malloc constructor memory-management exception-handling
我正在std::vector为自学教学目的设计一个类似的类,但我在构造函数中遇到了一个难以解决的内存分配问题.
该std::vector行为能力构造器是很方便,但也是有潜在的成本抛出一个std::bad_alloc异常,并采取了你的整个程序吧.
我奋力来决定什么是处理能力构造失败的情况不太可能发生的最优雅的方式,或最好的通知使用构造,他们同意该数据结构能够拿下整个程序的用户通过例外.
我首先想到的是添加一个编译时警告,只要调用构造函数,提醒,构造函数可能会失败,他们应该确保无论是处理它,或了解有关使用构造函数中的风险.
这个解决方案似乎很糟糕,因为如果在全球范围内应用它会引起太多警告,并给人留下不好的印象.
我的第二个想法是使构造函数成为私有的,并且需要通过类似于Singleton模式的静态"requestConstruct"方法来访问构造函数.
该解决方案使界面看起来很奇怪.
我还有一些想法,但所有这些想法似乎都会破坏界面的"感觉".这些想法是:
boost::optional还有一个很有趣的可能性就是没有足够的内存来实际捕获异常.这个程序似乎没有抓住它(这可能与有足够的内存有关,也可能没有).
#include <stdint.h>
#include <exception>
#include <iostream>
#include <stdlib.h>
int main(int argc, char **argv)
{
uint_fast32_t leaked_bytes = 0;
while (1) {
try {
new uint8_t;
} catch (const std::bad_alloc& e) {
std::cout << "successfully leaked" << leaked_bytes << " bytes." << '\n';
exit(0);
} catch (const std::exception& e) {
std::cout << "I caught an exception, but not sure what it was...\n";
exit(0);
}
++leaked_bytes;
}
}
Run Code Online (Sandbox Code Playgroud)
这个程序让我在程序终止之前处理失败,但是:
#include <stdlib.h>
#include <stdint.h>
#include <stdio.h>
int main(int argc, char **argv)
{
uint_fast32_t bytes_leaked = 0;
while (1) {
if (malloc(1) == 0) {
printf("leaked %u bytes.\n", bytes_leaked);
exit(0);
}
++bytes_leaked;
}
return 0;
}
Run Code Online (Sandbox Code Playgroud)
nothrow也正常工作:
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <new>
int main(int argc, char **argv)
{
uint64_t leaked_bytes = 0;
while (1) {
uint8_t *byte = new (std::nothrow) uint8_t;
if (byte == nullptr) {
printf("leaked %llu bytes.\n", leaked_bytes);
exit(0);
}
++leaked_bytes;
}
return 0;
}
Run Code Online (Sandbox Code Playgroud)
编辑:
我想我找到了解决这个问题的方法.在主流程上存储动态数据结构存在固有的天真.也就是说,这些结构不能保证成功,并且可能在任何时候都会破裂.
最好在另一个进程中创建所有动态结构,并在出现意外问题时使用某种重启策略.
这确实会增加与数据结构通信的开销,但它会阻止主程序管理数据结构可能出错的所有内容,这可以快速占用main中的大部分代码.
结束编辑.
是否有适当的方法来处理这些动态类中的分配问题,提高用户对这些风险的认识?
根据提供的反馈,我确信没有一种优雅的方法可以防止管理动态内存的类在不引入复杂性的情况下破坏您的程序。
抛出异常是有问题的,因为一旦你的类没有可以分配的内存,它可能无法处理用户可以捕获的 std::bad_alloc 。
经过更多思考,我意识到防止程序因它使用的模块而崩溃的一种方法是将使用这些模块的程序部分移动到另一个进程,并让该进程与主进程共享内存,这样,如果另一个进程以某种方式出现故障,您可以重新启动该进程并发出另一个请求。
只要您使用任何能够在极端情况下失败的类,就不可能阻止它们失败,除非您能够控制它们的极端情况。
对于动态内存,很难准确控制进程访问动态内存的方式、分配策略以及应用程序总共使用了多少内存。因此,如果不对您使用的连续内存池进行更严格的控制,或者将数据结构移至另一个可以在失败时重新启动的进程来管理,就很难控制它。
回答:本质上不可能同时提供管理动态内存的类的简单接口/实现对。您要么有一个简单的接口/实现来删除您的程序,例如 std::vector; 或复杂的接口/实现,需要以下之一或更聪明的东西: