首页 > 编程语言 >C++直接初始化和复制初始化

C++直接初始化和复制初始化

时间:2023-03-22 18:14:10浏览次数:34  
标签:初始化 自定义 CString C++ 复制 cs3 构造函数

引言

在 C++98 中有两种变量初始化方式:直接初始化和复制初始化(拷贝初始化)。

这两种初始化方式有着明显的差异,却由于编译器的优化而变得模糊。

  • 直接初始化语法形式:objType obj(params...);,如 int x(2);
  • 复制初始化语法形式:objType obj = param;,如 int x = 2;

其中复制初始化比较适合人类的阅读习惯,但其运行机制和性能与直接初始化有很大差异。

性能方面,对于内置类型,两种初始化语法在性能上几乎没有差异,而对于用户自定义类型却可能存在较大差异(取决于用户自定义类型的布局,用户自定义类型一般是 structclass,在 C++ 中两者已经没有区别,struct 就是一个成员访问权限都为 public class)。

值得一提的是,C++11 提供了花括号初始化方法,其语法形式是 objType obj{param1, param2,......},其目的是统一变量初始化方法,但却和其他新特性不兼容,例如auto,模板参数类型推导等等。

直接初始化和复制初始化的区别

上文提到,两种初始化方式的差异在用户自定义类型中更加明显,因此定义一个如下一个类:

class CString
{
private:
    char cs[64];

public:
    // 默认构造函数
    CString() {
        cs[0] = '\0';
        cout << "ctor: CString()" << endl; 
    }

    // 使用C风格字符串初始化
    CString(const char* pc) {
        strcpy(cs, pc);
        cout << "ctor: CString(const char* pc)" << endl;
    }

    // 复制构造函数
    // CString(const CString& c) {
    //     strcpy(cs, c.cs);
    //     cout << "ctor: CString(const CString& c)" << endl;
    // }

    // CString(const CString& c) = delete;

};


int main()  
{  
    CString cs1;   // 等价于CString cs1(), 调用默认构造函数
    
    CString cs2("hello, world.");	// 直接初始化
    CString cs3 = "hello, world.";	// 复制初始化

    CString cs4(cs3);	// 复制构造函数
    CString cs5 = cs3;	// 复制构造函数, 两者等价
    return 0;  
}

当启用复制构造函数时(第 19-23 行),代码能够编译运行,输出如下:

ctor: CString()
ctor: CString(const char* pc)
ctor: CString(const char* pc)
ctor: CString(const CString& c)
ctor: CString(const CString& c)

看起来,cs2 和 cs3 都调用了“使用C风格字符串初始化”的构造函数,直接初始化和复制初始化没有区别?

其实并非如此,当禁用复制构造函数时(第 25 行),再编译运行会得到如下错误:

error: use of deleted function 'CString::CString(const CString&)'
     CString cs3 = "hello, world.";

error: use of deleted function 'CString::CString(const CString&)'
     CString cs4(cs3);
     
error: use of deleted function 'CString::CString(const CString&)'
     CString cs5 = cs3;

cs3 - cs5 的初始化都失败了,3 个报错都是因为禁用了复制构造函数。cs4 和 cs5 用相同类型的对象进行初始化,调用复制构造函数,血脉纯正。而 cs3 的却有些不一样,它初始化使用的是一个 C 风格字符串,但从第 35 行上来看,非常像一种隐式类型转换:C 风格字符串对象转换为自定义类型 CString!

究其原因便是:cs3 初始化首先调用 CString(const char* pc) 构造一个临时对象 CString temp,然后编译器调用复制构造函数将 temp 复制到 cs3。 因此禁用复制构造函数后,cs3 初始化失败。

那既然 cs3 的初始化过程中编译器帮忙偷偷调用了复制构造函数,那为什么没有对应的输出呢?我也不知道,tnnd= =。

因此,当形参类型与自定义类型不相同时,自定义类型的复制初始化往往比直接初始化多一个临时对象的构造和析构成本,至于成本有多大,就要看该自定义类型的大小、复杂性了。

同时也可以发现一个问题:构造函数可以起到一种隐式类型转换的功能。

但其实关于自定义类型向其他类型转换,是有官方语法的,与本文主题不相关,向了解的话搜索关键词“类型转换运算符”。

要点总结

  1. 单个参数的构造函数存在隐式类型转换的功能(严格来说,这样的构造函数可以有多个参数,但只有一个参数没有指定默认值)
  2. 直接初始化通常比复制初始化成本低。直接初始化根据参数调用最合适的构造函数直接构造出对象,而复制初始化在被复制对象类型与自定义类型不一致时,存在临时对象的构造和析构成本。

标签:初始化,自定义,CString,C++,复制,cs3,构造函数
From: https://www.cnblogs.com/zwjason/p/17244976.html

相关文章

  • C++中&和&&的相关笔记
    目录1.引言2.&的作用2.1位运算2.2取地址2.3引用3.&&的用途3.1逻辑运算符AND3.2右值引用3.2.1背景知识3.2.2左值和右值3.2.3移动构造函数和移动赋值函数1.引言......
  • Vue3 点击复制功能,利用vue-clipboard3
    首先安装插件vue-clipboard3 npminstallvue-clipboard3--save然后在页面里面引入<buttonclass="btn"@click="copy()">点击复制</button>  建议用buttn标签......
  • C++调试方法总结(VS Code & VS & dbg)
    一、VSCodeC++程序调试1.1配置C++运行环境安装C/C++插件后打开C++设置界面:选择编译器、c和c++标准,以及inteliSenseMode之后会在当前.vscode目录下生成一个c_cpp_......
  • C/C++手机通信录[2023-03-22]
    C/C++手机通信录[2023-03-22]程序设计题目5:手机通信录【问题描述】用C/C++设计出模拟手机通信系统,能实现对手机中的通信录进行添加、修改、查询等功能。【基本要求】......
  • Autodesk 3d Max2020 初始化闪退
    事件起因:给同事安装完Autodesk3dMax2020 版本之后,软件初始化就闪退,后来在网上查了资料后解决。解决办法如下:services.msc-->Autodesk开头的服务都要改成自动启动......
  • C++数组类型中存入结构体类型对象
    最近看Binder机制的时候看到一个unsigned类型数组中不仅可以存放unsignedint类型还可以存放结构体对象,感到十分惊奇,下面我们来看一下uintptr_t类型和指针类型的区别uin......
  • C++ 字符串转16进制
    参考出处:https://blog.csdn.net/FinalCreed/article/details/71037420stringstring2hex(conststring&str){stringtemp;stringstreamss;stringresul......
  • C++查询ip归属地(QT)
    以查询ip归属地的例子来学习C++的API接口调用。常见的API接口可能会给出post及get两种访问方法,我们先学习较为简单的get方法。首先是找到相关的接口,如https://ip.userage......
  • 【转载】C++ 有用的资源
    https://www.runoob.com/cplusplus/cpp-useful-resources.html C++ 有用的资源以下资源包含了C++有关的网站、书籍和文章。请使用它们来进一步学习C++的知识。C+......
  • c++链表记录
    ListNode*pre=NULL;//定义一个空节点ListNode*tmp;//定义一个空的临时节点,此时tmp==NULL ListNode*cur=head;//定义一个等于节点head的节点 ListNode*du......