C++中构造函数和析构函数显式调用的方法

本文详细解析了C++中new运算符的三种用法:new运算符、new函数、placementnew,以及它们之间的区别。着重讨论了new在堆上分配内存并自动调用构造函数的功能,并对比了new函数与malloc的相似之处。此外,文章还介绍了如何通过重载new函数来实现自定义内存分配逻辑,并阐述了placementnew如何在已有内存上创建对象而不影响原有数据。

从网上摘抄:

 

构造:
#include <new>

C* c = static_cast<C*>( malloc( sizeof(C) ) );
try {
      new (c) C(a1, a2, a3, ... ); // a1,a2,a3是构造函数的参数
} catch () {
      free(c);
      throw;
}

析构:
c->~C();  // 显示调用
free(c);

 

以下为详细解释:

  • C++ new用法的正确方法应该如何操作?
  • 在这篇文章中我们将会根据其两种不同的含义分别介绍一下它的影音方法,希望能给大家带来一些帮助。
  • C++编程语言中有一种叫做new的术语。不过这一概念是比较模糊的,有些人把它理解为new函数,但是有的人又会把它理解为new运算符。那么它的真正含义又是如何的呢?在这里我们将会通过对C++ new用法的介绍,帮助大家一起分析一下。

     

    C++ new用法之一 new运算符

    最常用的是作为运算符的new,比如:

    string *str = new string(“test new”);

    作为运算符,new和sizeof一样,是C++内置的,你不能对它做任何的改变,除了使用它。

    new会在堆上分配一块内存,并会自动调用类的构造函数。

    C++ new用法之二 new函数

    第二种就是new函数,其实new运算符内部分配内存使用的就是new函数,原型是:

    void *operator new(size_t size);

    new函数返回的是一个void指针,一块未经初始化的内存。如你所见,这和C语言的malloc行为相似,你可以重载new函数,并且增加额外的参数,但是必须保证第一个参数必须是size_t类型,它指明了分配内存块的大小,C++允许你这么做,当然一般情况下这是不必要的。如果重载了new函数,在使用new操作符时调用的就是你重载后的new函数了。

    如果使用new函数,和语句string *str = new string(“test new”)相对的代码大概是如下的样子:

     

                
       
    1. string *str = (string*)operator new(sizeof(string));  
    2. str.string(“test new”);   
    3. // 当然这个调用时非法的,但是编译器是没有这个限制的 

     

    这还不算完,还有第三种的new存在。

    C++ new用法之三 placement new

    第三种,placement new,这也是new作为函数的一种用法,它允许你在一块已存在的内存上分配一个对象,而内存上的数据不会被覆盖或者被你主动改写,placement new同样由new操作符调用,调用格式是:

    new (buffer) type(size_t size);

    先看看下面的代码:

     

                
       
    1. char str[22];  
    2. int data = 123;  
    3. int *pa = new (&data) int;  
    4. int *pb = new (str) int(9); 

     

    结果*pa = 123(未覆盖原数据),而*pb = 9(覆盖原数据),可以看到placement new 并没有分配新的内存,也可以使用在栈上分配的内存,而不限于堆。

    为了使用placement new 你必须包含<new>或者<new.h>

    其实placement new和第二种一样,只不过多了参数,是函数new的重载,语法格式为:

    void *operator new(size_t, void* buffer);

    它看起来可能是这个样子:

    void *operator new(size_t, void* buffer) { return buffer;}

     

    和new对应的就是delete了,需要回收内存啊,不然就泄漏了,这个下次再写吧,回忆一下今天的内容先。

    总结

    1. 函数new

    void *operator new(size_t size); 在堆上分配一块内存,和placement new(void *operator new(size_t, void* buffer)); 在一块已经存在的内存上创建对象,如果你已经有一块内存,placement new会非常有用,事实上,它STL中有着广泛的使用。

    2. 运算符new

    最常用的new,没什么可说的。

    3. 函数new不会自动调用类的构造函数,因为它对分配的内存类型一无所知;而运算符new会自动调用类的构造函数。

    4. 函数new允许重载,而运算符new不能被重载。

    5. 紧接着就是对应的delete。

    以上就是对C++ new用法的详细介绍。


 

### 构造函数的作用及使用指南 构造函数C++中用于初始化对象的特殊成员函数,其主要作用是在对象创建时为其成员属性赋值。构造函数的名称与类名相同,并且没有返回值类型,包括`void`。构造函数可以被重载,这意味着一个类可以有多个构造函数,以支持不同的初始化方构造函数调用是由编译器自动完成的,无需手动调用。如果用户没有定义构造函数编译器会提供一个默认的构造函数,该构造函数不做任何事情。然而,当需要为对象的成员属性赋予特定值时,应该定义构造函数[^3]。 例如,考虑一个简单的`Data`类,它有一个字符指针成员`name`。为了确保`name`在对象创建时能够正确地初始化,可以定义一个带有参数的构造函数: ```cpp class Data { public: char *name; public: Data() { name = NULL; } Data(char *str) { name = (char*)calloc(1, strlen(str) + 1); strcpy(name, str); cout << "有参构造 name=" << name << endl; } }; ``` 在这个例子中,`Data`类有两个构造函数:一个是默认构造函数,另一个是接受一个字符指针作为参数的构造函数。后者负责分配内存并复制传入的字符串到`name`成员中[^4]。 ### 析构函数的作用及使用指南 析构函数是另一个特殊的成员函数,用于在对象生命周期结束时执行清理工作。析构函数的名字是在类名前加上波浪号`~`,并且没有参数也没有返回值类型。每个类只能有一个析构函数,且不能被重载。如果用户没有定义析构函数编译器会提供一个默认的析构函数,该析构函数同样不做任何事情[^2]。 对于包含指针成员的类来说,定义析构函数尤为重要,因为需要确保指针指向的内存被正确释放,防止内存泄漏。继续使用上面的`Data`类为例,其中定义了一个析构函数来释放`name`指针指向的内存: ```cpp ~Data() { cout << "析构函数" << name << endl; if (name != NULL) { free(name); name = NULL; } } ``` 这段代码确保了当`Data`对象的生命期结束时,`name`所指向的内存会被释放,并将`name`设置为`NULL`以避免悬挂指针的问题。 ### 构造函数析构函数调用顺序 在继承关系中,构造函数析构函数调用顺序遵循特定规则。构造函数按照从基类到派生类的顺序调用,而析构函数则相反,从派生类到基类的顺序调用。这种顺序确保了对象的正确初始化清理[^1]。 此外,如果一个类包含其他类类型的成员对象,则这些成员对象的构造函数会在包含类的构造函数体执行之前被调用。同样,这些成员对象的析构函数会在包含类的析构函数体执行之后被调用[^5]。 ### 示例代码 下面是一个完整的示例,展示了构造函数析构函数的基本用法: ```cpp #include <iostream> #include <stdlib.h> #include <string.h> using namespace std; class Data { public: char *name; public: Data() { name = NULL; } Data(char *str) { name = (char*)calloc(1, strlen(str) + 1); strcpy(name, str); cout << "有参构造 name=" << name << endl; } ~Data() { cout << "析构函数" << name << endl; if (name != NULL) { free(name); name = NULL; } } }; void test() { Data ob("hello world"); } int main() { test(); return 0; } ``` 在这个示例中,`test`函数创建了一个`Data`对象`ob`,并传递了一个字符串`"hello world"`给构造函数。当`test`函数结束时,`ob`对象的生命周期结束,析构函数调用,释放了`name`所指向的内存。 ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值