C++面试八股文:如何在堆上和栈上分配一块内存?

打印 上一主题 下一主题

主题 935|帖子 935|积分 2805

某日二师兄参加XXX科技公司的C++工程师开发岗位6面:
面试官: 如何在堆上申请一块内存?
二师兄:常用的方法有malloc,new等。
面试官:两者有什么区别?
二师兄:malloc是向操作系统申请一块内存,这块内存没有经过初始化,通常需要使用memset手动初始化。而new一般伴随三个动作,向操作系统申请一块内存,并执行类型的默认构造函数,然后返回类的指针。
面试官:嗯,那你知道calloc和realloc吗?
二师兄:calloc比malloc多做了一步,就是把申请的内存初始化成0。而realloc则可以改变当前指针所指向的内存块的大小。
面试官:好的。那么你知道这些api/操作符失败会发生什么吗?
二师兄:malloc/calloc/realloc失败会返回NULL,而new失败则会抛出异常。
面试官:有没有让new失败不抛出异常的方法?
二师兄:好像有,但是我不记得了。。。
面试官:没关系。。。我们都知道new和delete成对出现,new[]和delete[]也是成对出现,那么我想问,如果使用new[]创建的对象用delete释放了会发生什么?为什么?
二师兄:额。。。内存泄漏?对,会发生内存泄漏。因为内存没有被释放。
面试官:好的。我们都知道C++中的内存管理是一个比较麻烦的事情,现在有个需求,需要在程序中记录主动申请的内存和主动释放的内存,以确保没有发生内存泄漏。有什么好的方法吗?
二师兄:可以重载new和delete运算符。
面试官:如何重载new和delete运算符?
二师兄:我得查一下资料,这个重载用的很少。。。
面试官:(笑)好吧,最后一个问题,咱们上面一直在讨论堆中的内存的分配和释放,请问一下,如果在栈上分配一块固定的内存?栈中的内存如何释放?
二师兄:额。。。(思考)使用 char[size] ? 应该不需要手动释放。
面试官:好的,回去等通知吧。
对于二师兄的表现,小伙伴们能给打几分呢?我们先看看二师兄在面试中表现不太好的地方:
面试官:有没有让new失败不抛出异常的方法?
在C++中我们可以使用以下方法使得new运算符不抛出异常,
  1. int* p = new (std::nothrow) int(42);
  2. if(p == nullptr)
  3. {
  4.     //分配失败
  5. }
复制代码
这个特性需要C++11支持。
再看下一个问题:
如果使用new[]创建的对象用delete释放了会发生什么?
一定会发生内存泄漏吗?答案是,不一定。这取决于类型T。我们先看第一种情况:
  1. class Foo
  2. {
  3. public:
  4.     Foo():num_(42){}
  5. private:
  6.     int num_;
  7. };
  8. Foo* pf = new Foo[1024];
  9. delete pf;
复制代码
当类型T没有管理资源时,delete pf会把整个申请的1024个Foo所占用的内存全部归还给操作系统,此时并没有内存泄漏。再看下一种情况:
  1. class Foo
  2. {
  3. public:
  4.     Foo():num_(new int(42)){}
  5.     ~Foo(){delete num_;}
  6. private:
  7.     int* num_;
  8. };
  9. Foo* pf = new Foo[1024];
  10. delete pf;
复制代码
此时会造成内存泄漏,原因很简单。在执行delete[]时,首先逆序执行每个元素的析构函数,然后再把整块内存归还给操作系统。而delete只会把内存还给操作系统,没有执行析构函数。当类没有资源需要管理时,执行与不执行析构函数都无关紧要,但是当类中需要管理资源时,析构函数的执行就至关重要了。
如何重载new和delete运算符?
[code]#include #include #include struct MemoryInfo {    size_t size;    const char* file;    int line;};std::map memoryMap;void* operator new(size_t size, const char* file, int line) {    void* ptr = std::malloc(size);    memoryMap[ptr] = {size, file, line};    return ptr;}void operator delete(void* ptr) noexcept {    auto it = memoryMap.find(ptr);    if (it != memoryMap.end()) {        std::free(ptr);        memoryMap.erase(it);    }}#define new new(__FILE__, __LINE__)int main() {    int* p = new int(42);    for (const auto& [ptr, info] : memoryMap) {        std::cout
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

郭卫东

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表