interview
cpp-basics
C++中new和malloc的区别?delete和free的区别?

C++基础面试题, C++ 中 new 和 malloc 的区别?delete 和 free 的区别?

C++基础面试题, C++ 中 new 和 malloc 的区别?delete 和 free 的区别?

QA

Step 1

Q:: C++ 中 new 和 malloc 的区别是什么?

A:: new 是 C++ 中的运算符,用于动态分配内存,并自动调用相应类的构造函数。而 malloc 是 C 标准库中的函数,只分配内存,不调用构造函数。new 返回的是对象类型的指针,而 malloc 返回的是 void*,需要进行类型转换。此外,new 分配失败时会抛出 std::bad_alloc 异常,而 malloc 返回 NULL。

Step 2

Q:: delete 和 free 的区别是什么?

A:: delete 是 C++ 中用于释放通过 new 分配的内存,并调用对象的析构函数,而 free 是 C 标准库函数,用于释放 malloc 分配的内存,但不会调用析构函数。如果使用 delete 释放 malloc 分配的内存,或用 free 释放 new 分配的内存,可能会导致未定义行为。

Step 3

Q:: 为什么 new 和 delete 会调用构造函数和析构函数?

A:: C++ 是面向对象的编程语言,new 和 delete 调用构造函数和析构函数是为了支持对象的生命周期管理。当使用 new 创建对象时,需要初始化该对象,调用构造函数可以保证对象的正确初始化。而在 delete 对象时,析构函数确保资源的正确释放。

Step 4

Q:: new 和 delete 是否可以重载?如果可以,如何重载?

A:: 是的,new 和 delete 可以被重载。通过重载 new,开发者可以定制内存分配的方式,比如增加内存池或进行日志记录。同样,重载 delete 可以定制内存释放的方式。重载时需要遵循特定的函数签名:void* operator new(size_t size)void operator delete(void* ptr)

Step 5

Q:: 在实际编程中,何时应该使用 new/delete 而不是 malloc/free?

A:: 在 C++ 编程中,如果涉及到对象的构建和析构,应该使用 new/delete,因为它们能够确保构造函数和析构函数被正确调用。如果只是简单的内存分配而不涉及对象的初始化或清理,malloc/free 可能更合适,尤其是在需要与 C 库交互时。

用途

面试这一类问题的目的是为了考察候选人对 C`++ 内存管理的理解,尤其是在动态内存分配与对象生命周期管理方面的知识。在实际生产环境中,选择合适的内存分配和释放机制是确保程序稳定性和性能的重要因素。对于大型项目中的内存管理,了解 new/delete 和 malloc/`free 的区别以及何时使用它们可以避免内存泄漏、未定义行为等常见问题。\n

相关问题

🦆
C++ 中的智能指针如 std::unique_ptr, std::shared_ptr是什么?

智能指针是 C++11 引入的标准库模板,用于自动管理动态分配的内存,避免显式调用 delete。std::unique_ptr 是独占所有权的智能指针,不可复制,只能转移所有权。std::shared_ptr 是共享所有权的智能指针,允许多个指针共享同一个资源,资源在最后一个指针销毁时被释放。

🦆
C++ 中的 RAII 是什么?

RAII(Resource Acquisition Is Initialization)是一种编程惯用法,资源在对象创建时被分配(或获取),并在对象销毁时被释放。它依赖于对象的构造函数和析构函数,确保资源管理的安全性和简洁性。智能指针是 RAII 的一个典型例子。

🦆
如何避免内存泄漏?

内存泄漏可以通过确保每个 new/delete 成对使用来避免。此外,使用智能指针(如 std::unique_ptr 或 std::shared_ptr)可以自动管理内存,防止手动管理时可能出现的错误。工具如 Valgrind 也可以用于检测和分析内存泄漏问题。

🦆
C++ 中的浅拷贝和深拷贝的区别是什么?

浅拷贝只是简单复制对象的值,不考虑对象内部指针指向的内存。而深拷贝会复制对象本身以及它所指向的内存,确保两个对象独立存在。对于含有动态内存的类,通常需要定义深拷贝以避免多个对象共享同一块内存。

🦆
在多线程环境下如何安全地分配和释放内存?

在多线程环境中,必须确保内存分配和释放的操作是线程安全的。可以使用 C++11 引入的 std::mutex 或更高级的并发控制机制(如 std::atomic、std::shared_mutex)来保护临界区。此外,使用线程安全的数据结构和容器(如 C++ 标准库中的线程安全版本)也是一种有效的策略。