new完之后不delete,变量会一直保存

本文展示了一个使用C++编写的简单程序,该程序通过一个包含虚函数的类来演示多态的概念。程序中定义了一个名为aa的基类,其中包含一个虚函数set用于设置成员变量a的值。通过动态分配内存创建了该类的一个实例,并将其地址存放在一个指向基类的指针数组中。最后程序输出了通过指针访问并设置的成员变量a的值。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

#include "stdafx.h"
#include <iostream>
using namespace std;


class aa
{
public:
int a;
virtual void set(int i)
{
a = i;
}
};
aa* cc[4];
void chuangjian()
{
aa* b = new aa;
b->set(73);
cc[1] = b;
}


int main()
{
    chuangjian();
    cout << cc[1]->a << endl;
    system("pause");
    return 0;

}

依旧会输出73

<think>我们正在讨论C++中重载newdelete运算符后如何恢复默认行为。根据引用资料,我们知道重载newdelete运算符可以是全局的,也可以是类内部的。恢复默认行为的方法取决于我们如何重载它们。 首先,回顾一下引用内容: [^2]提到:当我们为类定义了operator new()和operator delete()函数以后,编译器就再调用全局的同名函数,而是调用我们自己定义的版本。 [^3]提到:重载函数可以是全局函数,也可以是类内部的公有重载函数;当既有全局的重载函数,也有类内部的公有重载函数时,实际调用的是类内部的公有重载函数。 因此,恢复默认行为的方法有两种情况: 1. 对于类特定的重载:如果我们重载的是某个类内部的operator new和operator delete,那么我们可以通过使用全局作用域运算符`::`来显式调用全局的newdelete。例如,在类内部使用`::new`和`::delete`。 2. 对于全局重载:如果我们重载了全局的operator new和operator delete,那么恢复默认行为就比较复杂,因为全局重载会影响整个程序。通常,我们建议重载全局的newdelete,因为这样会影响所有内存分配。如果已经重载了,我们可以通过保存原来的函数指针,然后在需要的时候调用原来的函数。 具体方法如下: ### 类特定重载的恢复 在类内部,我们可以通过作用域解析运算符来调用全局版本。 例如,假设我们有一个类`MyClass`,它重载了newdelete: ```cpp class MyClass { public: void* operator new(size_t size) { std::cout << "Custom new for MyClass" << std::endl; return malloc(size); } void operator delete(void* ptr) { std::cout << "Custom delete for MyClass" << std::endl; free(ptr); } }; ``` 如果我们想在类内部某个成员函数中或者类外部创建对象时使用默认的全局newdelete,可以这样做: ```cpp // 使用类自定义的new MyClass* obj1 = new MyClass; delete obj1; // 使用全局的newdelete MyClass* obj2 = ::new MyClass; // 使用全局new ::delete obj2; // 使用全局delete ``` ### 全局重载的恢复 如果我们重载了全局的newdelete,那么我们需要在重载的函数中提供一种机制来切换回默认行为,或者保存默认的函数指针以便调用。 但是,C++标准并没有提供直接的方法来获取默认的全局operator newdelete的函数指针。因此,一种常见的做法是在重载之前保存原来的函数指针。 例如: ```cpp #include <iostream> #include <cstdlib> // 声明原始的函数指针类型 typedef void* (*new_func)(size_t); typedef void (*delete_func)(void*); // 保存原来的函数指针 new_func original_new = nullptr; delete_func original_delete = nullptr; // 重载全局operator new void* operator new(size_t size) { std::cout << "Custom global new" << std::endl; if (original_new) { return original_new(size); } return malloc(size); } // 重载全局operator delete void operator delete(void* ptr) noexcept { std::cout << "Custom global delete" << std::endl; if (original_delete) { original_delete(ptr); } else { free(ptr); } } // 一个函数用于保存原始的函数指针(在重载之前,我们需要先保存) void save_original_operators() { // 如何获取原始的?实际上,在重载之前我们可以通过函数指针来获取,但是一旦重载,原来的就被覆盖了。 // 所以,我们必须在重载之前保存。因此,这个方案需要在程序启动时,在重载之前先保存。 // 但是,如果我们已经重载了,那么就无法直接获取了。因此,这种方法需要在重载之前保存。 } // 恢复默认行为:实际上,我们可以通过设置一个开关,或者将原始函数指针暴露出来,然后让用户可以选择调用原始版本。 // 但是,如果我们已经重载了全局的,那么所有newdelete都会走我们的重载版本。因此,我们可以在重载版本中通过条件判断来调用原始版本。 // 然而,更好的做法是:在重载全局new/delete之前,先保存原始的函数指针。这样在重载函数内部,我们可以通过函数指针调用原始版本。 // 但是,注意:在程序启动时,我们如何保存?我们可以使用一个静态变量,在重载函数第一次被调用之前初始化它(但是要注意初始化顺序)。 // 实际上,我们可以通过链接期技巧来获取原始的函数指针,但是C++标准没有提供,所以可移植。 // 因此,通常做法是:在重载之前,保存原始的函数指针(例如在动态库中,可以通过dlsym获取,但在C++中标准方法没有)。 // 所以,如果已经重载了全局的new/delete,并且没有事先保存,那么恢复默认行为就比较困难。 // 建议:除非必要,要重载全局的new/delete。如果必须重载,那么最好在重载函数内部调用原始的(通过事先保存的指针),并且提供一种机制来切换。 ``` 由于全局重载的恢复比较复杂,且可移植,所以通常建议避免重载全局的newdelete。如果必须重载,那么在重载之前保存原始的函数指针,并在需要时使用。 ### 总结 1. 对于类特定的重载:使用`::new`和`::delete`来调用全局版本。 2. 对于全局重载:在重载之前保存原始函数指针,并在重载函数中根据需要调用原始版本。但注意,全局重载影响广泛,需谨慎。 注意:在类内部重载时,使用全局作用域的newdelete可以绕过类的重载版本,直接使用全局版本。 因此,针对用户的问题,如果是在类内部重载,恢复默认行为的方法就是使用`::new`和`::delete`。如果是全局重载,则需要在重载前保存原始函数指针,然后通过该指针调用原始版本。 ### 相关问题 1. 在C++中,重载newdelete运算符有哪些常见的应用场景? 2. 如何为特定类重载new[]和delete[]运算符? 3. 重载全局newdelete运算符时需要注意哪些问题? 4. 在C++中,如何实现自定义内存管理策略?</think>### C++ 重载 newdelete 运算符后恢复默认行为的方法 在 C++ 中重载 `new` 和 `delete` 运算符后,可通过以下方式恢复默认行为: #### 1. **类内重载的恢复方法** 当在**特定类内**重载运算符时,使用全局作用域运算符 `::` 显式调用默认版本: ```cpp class MyClass { public: // 类内重载 new void* operator new(size_t size) { std::cout << "Custom new\n"; return malloc(size); } // 类内重载 delete void operator delete(void* ptr) { std::cout << "Custom delete\n"; free(ptr); } }; // 恢复默认行为:使用全局 new/delete MyClass* obj = ::new MyClass; // 调用全局 new ::delete obj; // 调用全局 delete ``` - **关键点**:`::new` 和 `::delete` 绕过类内重载版本,直接调用全局默认运算符[^1][^3]。 #### 2. **全局重载的恢复方法** 若重载了**全局运算符**,需保存原始函数指针,通过函数指针调用默认行为: ```cpp #include <new> #include <iostream> // 保存原始函数指针 void* (*original_new)(size_t) = nullptr; void (*original_delete)(void*) = nullptr; // 重载全局 new void* operator new(size_t size) { std::cout << "Global custom new\n"; return malloc(size); } // 重载全局 delete void operator delete(void* ptr) noexcept { std::cout << "Global custom delete\n"; free(ptr); } // 恢复默认行为的函数 void restore_default_operators() { original_new = ::operator new; // 获取默认 new 地址 original_delete = ::operator delete; // 获取默认 delete 地址 } // 使用默认行为分配内存 void* ptr = original_new(100); // 调用原始 new original_delete(ptr); // 调用原始 delete ``` - **注意事项**: - 需在首次调用 `new`/`delete` **前**保存原始指针(通常在程序初始化时成)[^3][^4]。 - 全局重载影响整个程序,需谨慎使用[^4]。 #### 3. **关键原则总结** | 场景 | 恢复方法 | 注意事项 | |--------------|-----------------------------------|----------------------------| | **类内重载** | 使用 `::new` 和 `::delete` | 仅影响该类的对象 | | **全局重载** | 通过函数指针调用原始运算符 | 需提前保存原始函数指针 | > ⚠️ **重要提示**: > 全局 `new`/`delete` 重载会覆盖所有内存操作,可能导致第三方库行为异常。建议优先使用类内重载,并通过 `::` 运算符按需恢复默认行为[^2][^4]。 ### 相关问题 1. 类内重载 `new`/`delete` 时,如何避免影响继承类的内存分配? 2. 重载全局 `new` 和 `delete` 可能引发哪些兼容性问题? 3. 如何通过 RAII 模式安全地管理自定义内存分配器的生命周期? 4. C++17 引入的 `std::aligned_alloc` 与自定义 `new` 重载有何关联? [^1]: 重载 `delete` 时参数为 `void*`,此时对象析构已成,仅需释放原始内存。 [^2]: 类内重载优先于全局重载,通过作用域解析可调用全局版本。 [^3]: 保存原始运算符指针是实现全局重载恢复的核心机制。 [^4]: 除非必要,建议重载全局内存管理运算符,易引发可预测问题。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值