区分C++中的&和&&

c++的&和&&是两个常用且容易让人混淆迷惑的运算符,其中&符号有三种用途,&&有两种。本文对这两个运算符的用途做简要总结。

&的用途

第一种用途:位运算中的“与”(AND)。位运算十分高效,数据分片时常会用到,例如网络数据报头、IP地址段、UTF-8编码等。

第二种用途:取地址。这个功能在C中比较常见,比如取函数地址、变量地址。用法示例:

int b = 10;
int *a = &b; // a指针指向b的存储地址

// 声明函数
int add(int a, int b) {return a + b}
// 声明函数指针类型
int (*functionPtr)(int, int);
// 声明和初始化指针, &取函数的地址
functionPtr addPtr = &add;

第三种用途:引用。这个功能是C++的补充,常用在函数传参(C中一般用指针)、临时变量引用等。用法示例:

// 声明v1和v2两个参数引用传递
template <typename T>
T product(const std::vector<T>& v1, const std::vector<T>& v2) {...}

std::vector<std::vector<int> > vecs(10);
// 引用取出数组里的值,避免复制
auto& vec = vecs[0];

可以看到,三种用法都很基础,使用上很简单。

&&的用途

第一种用途:“与”(AND)逻辑运算符。做条件判断时,&&常用来连接多个条件。

第二种用途:右值引用,这个功能自C++11起才可用。移动语义是C++11新增的重要功能,其重点是对右值的操作。右值可以看作程序运行中的临时结果,右值引用可以避免复制提高效率。&&用法示例:

#include <iostream>
struct Foo {
 ~Foo() {std::cout << "destruction" << std::endl;}
};

Foo FooFactory() {
 return Foo();
}

int main() {
 std::cout << "before copy constructor..." << std::endl;
 Foo foo1 = FooFactory();
 std::cout << "after copy constructor..." << std::endl << std::endl;
 // 引用右值,避免生成新对象
 Foo&& foo2 = FooFactory();
 std::cout << "life time ends!" << std::endl << std::endl;

 return 0;
}

clang编译器(加-fno-elide-constructors选项)编译上述代码, 运行结果如下:

before copy constructor...
destruction
destruction
after copy constructor...

destruction
life time ends!

destruction
destruction

从输出结果看,第二种写法少了一次destruction输出。这意味着通过右值引用(&&),foo2直接引用FooFactory返回的对象,避免了对象复制。

注意: 由于“复制省略(Copy elision)”优化技术,一些编译器输出可能与上述不同。例如g++编译器会略过临时对象复制以优化性能。g++ 4.8.5编译程序输出结果如下:

before copy constructor...
after copy constructor...

life time ends!

destruction
destruction

clang编译的结果对比,省去了三次临时对象的生成、析构。

参考

https://stackoverflow.com/questions/13099603/c11-move-constructor-not-called-default-constructor-preferred

以上就是区分C++的&和&&的详细内容,更多关于C++ &和&&的资料请关注我们其它相关文章!

(0)

相关推荐

  • c++中#include &lt;&gt;与#include""的区别详细解析

    首先是区别: <>先去系统目录中找头文件,如果没有在到当前目录下找.所以像标准的头文件 stdio.h.stdlib.h等用这个方法. 而""首先在当前目录下寻找,如果找不到,再到系统目录中寻找. 这个用于include自定义的头文件,让系统优先使用当前目录中定义的. 然后是使用习惯的问题: 假设A是常被包含的文件. 则A中写的应该是一些 常用的函数,和一些宏定义.而且,不能出现main函数.

  • C++中引用(&)的用法与应用实例分析

    对于习惯使用C进行开发的朋友们,在看到c++中出现的&符号,可能会犯迷糊,因为在C语言中这个符号表示了取地址符,但是在C++中它却有着不同的用途,掌握C++的&符号,是提高代码执行效率和增强代码质量的一个很好的办法. 引用是C++引入的新语言特性,是C++常用的一个重要内容之一,正确.灵活地使用引用,可以使程序简洁.高效.我在工作中发现,许多人使用它仅仅是想当然,在某些微妙的场合,很容易出错,究其原由,大多因为没有搞清本源.故在本篇中我将对引用进行详细讨论,希望对大家更好地理解和使用引用起

  • c++中vector&lt;int&gt;和vector&lt;int*&gt;的用法区别

    在使用STL容器(比如map.list.vector等)的时候,是用放一个对象还是放一个对象指针,即是用vector<int>还是vector<int*>,这里的vector可以换成其他的容器,int可以换成其他基本类型,也可以自定义的数据结构或类. 首先,要说明的是,这两种方式,怎么用都可以实现功能,把一组整型数放到容器里.先看看两种方式在使用的时候的区别. 1.vector<int> 复制代码 代码如下: vector<int> vecTemp;for

  • C++ 中dynamic_cast&lt;&gt;的使用方法小结

    即会作一定的判断.        对指针进行dynamic_cast,失败返回null,成功返回正常cast后的对象指针:        对引用进行dynamic_cast,失败抛出一个异常,成功返回正常cast后的对象引用. 注意:dynamic_cast在将父类cast到子类时,父类必须要有虚函数.例如在下面的代码中将CBasic类中的test函数不定义成        virtual时,编译器会报错:error C2683: dynamic_cast : "CBasic"不是多态

  • 区分java中String+String和String+char

    我们来考虑一个关于java中String的问题: "abc" + '/'和 "abc" + "/"的区别. 通过这个例子, 我们可以顺便练习一下JDK工具中javap的用法, 原问题是这样的: 把斜杠/当作字符或字符串有什么区别呢? 一个是当作基本数据类型char,一个是对象String.具体有什么区别呢? 当作字符效率会更高吗? String str = "abc" + '/'; 和 String str = "a

  • 如何区分JAVA中的equals与==

    java中的数据类型,可分为两类: 1.基本数据类型,也称原始数据类型. byte,short,char,int,long,float,double,boolean  他们之间的比较,应用双等号(==),比较的是他们的值. 基本数据类型比较 == 和 Equals 两者都是比较值:equals()与==都是java中用于进行比较的,返回boolean值,不同的是equals()是Object类中定义的一个方法,==是一个比较运算符.下面是equals()在Object中的源码: public b

  • 如何区分C++中的inline和#define宏

    (1)什么是内联函数? 内联函数是指那些定义在类体内的成员函数,即该函数的函数体放在类体内. (2)为什么要引入内联函数? 当然,引入内联函数的主要目的是:解决程序中函数调用的效率问题. 另外,前面我们讲到了宏,里面有这么一个例子: #define ABS(x) ((x)>0? (x):-(x)) 当++i出现时,宏就会歪曲我们的意思,换句话说就是:宏的定义很容易产生二意性. (3)为什么inline能取代宏? 1. inline 定义的类的内联函数,函数的代码被放入符号表中,在使用时直接进行替

  • 如何区分JAVA中的throws和throw

    throws和throw: throws:用来声明一个方法可能产生的所有异常,不做任何处理而是将异常往上传,谁调用我我就抛给谁. 用在方法声明后面,跟的是异常类名 可以跟多个异常类名,用逗号隔开 表示抛出异常,由该方法的调用者来处理 throws表示出现异常的一种可能性,并不一定会发生这些异常 throw:则是用来抛出一个具体的异常类型. 用在方法体内,跟的是异常对象名 只能抛出一个异常对象名 表示抛出异常,由方法体内的语句处理 throw则是抛出了异常,执行throw则一定抛出了某种异常 分别

  • 区分python中的进程与线程

    今天整理的文章是给大家梳理Python的进程与线程的区别,没什么代码,希望大家能清楚知道他们的区别,什么情况用线程,什么情况用进程做到心中有数,希望大家能熟练掌握. 进程的基本概念 概念 进程就是一个程序在一个数据集上的一次动态执行过程.进程一般由程序.数据集.进程控制块三部分组成.我们编写的程序用来描述进程要完成哪些功能以及如何完成:数据集则是程序在执行过程中所需要使用的资源:进程控制块用来记录进程的外部特征,描述进程的执行变化过程,系统可以利用它来控制和管理进程,它是系统感知进程存在的唯一标

  • 区分shell中的 反引号、$()和${}

    1.反引号与$()用于命令替换 反引号和$()的作用相同,用于命令替换(command substitution),即完成引用的命令的执行,将其结果替换出来,与变量替换差不多.比如: echo `date '--date=1 hour ago' +%Y-%m-%d-%H` #或者 echo $(date '--date=1 hour ago' +%Y-%m-%d-%H) 输出结果是相同的: 2019-02-02-09. 在编写Shell脚本时建议使用$(),原因主要有: (1)反引号与单引号外形

  • 区分Java中的ArrayList和LinkedList

    一:ArrayList和LinkedList的大致区别如下: 1.ArrayList是实现了基于动态数组的数据结构,ArrayList实现了长度可变的数组,在内存中分配连续的空间.遍历元素和随机访问元素的效率比较高 2.LinkedList基于链表的数据结构, 插入.删除元素时效率比较高  故:[插入.删除操作频繁时,可使用LinkedList来提高效率]LinkedList提供对头部和尾部元素进行添加和删除操作的方法,插入/删除第一个和最后一个效率比较高: 3:ArrayList和Linked

  • 区分c++中的声明与定义

    C++编码过程中,我们经常谈及"定义"和"声明",二者是编程过程中的基本概念.我们需要使用一个变量.类型(类.结构体.枚举.共用体)或者函数时,我们需要提前定义和声明.定义和声明的过程,就像我们向图书馆借阅书籍一般,需要先完成书籍的印刷,即创造出书籍,这是一个定义的过程,有了书籍,我们需要到图书馆完成借阅的登记手续,这是申明的过程.完成了申明,我们有了使用书籍的权限,就可以尽情的畅游在知识的海洋.如果说书籍是自己委托印刷厂印刷的,那么你无需向他人借阅,即无需声明,可

  • 如何区分vue中的v-show 与 v-if

    1. v-show 不管初始的条件是什么,元素总是会被渲染,并且只是简单的基于 CSS display: none 或者 display: block 的属性进行切换. 2. v-if 会根据初始的条件(data里自己的定义的数据)来进行真正的渲染(组件真正的销毁和重建),如果条件为真,才会开始渲染条件块,如果条件为假,则不会渲染条件块. 注意: v-if不要和v-for一起使用! 当和 v-for 一起使用时,v-for 的优先级比 v-if 更高,详见 vue官网关于 v-for 的详细描述

  • 区分C# 中的 Struct 和 Class

    翻译自 Manju lata Yadav 2019年6月2日 的博文 <Difference Between Struct And Class In C#>,补充了一些内容和示例. 结构体(struct)是类(class)的轻量级版本.结构体是值类型,可用于创建行为类似于内置类型的对象. 比较 结构体和类共享许多特性,但与类相比有以下局限性. 结构体不能有默认构造函数(无参构造函数)或析构函数,构造函数中必须给所有字段赋值. public struct Coords { public doub

随机推荐