首页 > 编程语言 >C++ explicit&noexcept关键字

C++ explicit&noexcept关键字

时间:2024-10-06 11:59:56浏览次数:6  
标签:函数 noexcept explicit C++ MyClass 隐式 构造函数

C++ explicit&noexcept关键字

explicit关键字

在 C++ 中,explicit 关键字用于避免编译器在特定情况下进行隐式类型转换。它主要作用于构造函数和转换函数,防止不必要或意外的类型转换发生,从而提高代码的安全性和可读性。

1. 作用于构造函数

当一个构造函数只接受一个参数时,它通常会被编译器视为可以进行隐式类型转换。例如,如果你定义一个构造函数允许通过单个参数初始化对象,编译器可能会将该参数自动转换为对象类型。这种隐式转换有时可能会导致难以调试的错误。

explicit 关键字可以禁止这种隐式转换,使得构造函数只能用于显式地创建对象。

示例(没有 explicit):

class MyClass {
public:
    MyClass(int x) { }
};

int main() {
    MyClass obj = 10;  // 隐式调用 MyClass(10)
}

在这个例子中,MyClass 的构造函数可以隐式地将 10 转换为 MyClass 类型的对象。

使用 explicit 禁止隐式转换:

class MyClass {
public:
    explicit MyClass(int x) { }
};

int main() {
    // MyClass obj = 10;  // 错误:不能隐式转换
    MyClass obj(10);      // 正确:必须显式调用构造函数
}

这里,通过添加 explicit 关键字,编译器会拒绝隐式转换,要求必须显式调用构造函数。

2. 作用于转换函数

转换函数(即 operator 函数)可以将一个类的对象转换为其他类型。在某些情况下,自动的类型转换可能会带来意想不到的结果,因此 explicit 也可以用于修饰转换函数,以禁止隐式转换。

示例(没有 explicit):

class MyClass {
public:
    operator int() const { return 42; }
};

int main() {
    MyClass obj;
    int x = obj;  // 隐式调用转换函数,将 obj 转换为 int 类型
}

使用 explicit 禁止隐式转换:

class MyClass {
public:
    explicit operator int() const { return 42; }
};

int main() {
    MyClass obj;
    // int x = obj;  // 错误:不能隐式转换
    int x = static_cast<int>(obj);  // 正确:必须显式转换
}

这里,explicit 禁止了隐式转换,需要使用 static_cast 进行显式转换。

总结:

  • 构造函数explicit 用于防止通过单参数构造函数的隐式类型转换,要求显式创建对象。
  • 转换函数explicit 用于禁止类对象到其他类型的隐式转换,要求显式调用转换函数。

noexcept关键字

在 C++ 中,noexcept 是一个关键字,用于指定一个函数是否承诺不抛出异常。它的主要作用是告诉编译器和程序员,这个函数在正常情况下不会抛出异常,从而可以进行某些优化和错误处理。

noexcept 的作用:

  1. 声明函数不会抛出异常
    当一个函数被标记为 noexcept,它承诺不会抛出异常。如果该函数在运行时确实抛出了异常,程序会直接调用 std::terminate() 并中止执行,而不会像正常的异常处理流程那样进行栈展开。

    例如:

    void foo() noexcept {
        // 函数体不会抛出异常
    }
    
  2. 优化编译器行为
    标记为 noexcept 的函数可以让编译器进行更好的优化,特别是在那些涉及异常处理的代码路径上。编译器知道不需要生成栈展开(stack unwinding)代码来处理异常,因为 noexcept 承诺不会抛出异常。

  3. 与异常安全性有关
    在异常安全的代码中,noexcept 有助于编写更具鲁棒性(健壮性)的代码。某些标准库的操作(例如容器的某些操作)在处理涉及 noexcept 的函数时,行为可能会有所不同。例如,std::vector 的移动操作要求其元素的移动构造函数是 noexcept 的,否则在扩展容量时会回退到复制操作。

  4. 条件性的 noexcept
    noexcept 可以是条件性的,即你可以根据某些条件决定函数是否是 noexcept。这种情况主要用于模板代码,确保模板实例化时只有在某些条件下才标记为 noexcept

    例如:

    template <typename T>
    void foo(T&& t) noexcept(noexcept(T())) {
        // 根据 T 的构造函数是否抛出异常来决定是否是 noexcept
    }
    

使用场景:

  1. 移动构造函数和移动赋值运算符
    如果一个类的移动构造函数或移动赋值运算符被标记为 noexcept,那么标准库容器在移动该对象时会更高效。例如:

    class MyClass {
    public:
        MyClass(MyClass&&) noexcept = default;
        MyClass& operator=(MyClass&&) noexcept = default;
    };
    
  2. 析构函数
    通常,析构函数默认是 noexcept。因为在异常传播时,如果析构函数抛出异常,C++ 会调用 std::terminate()

    例如:

    class Foo {
    public:
        ~Foo() noexcept {
            // 不应抛出异常
        }
    };
    

noexceptthrow() 的区别:

noexcept 是 C++11 引入的,取代了早期的 throw() 异常规范。throw() 的语义是标记函数不会抛出任何类型的异常,但它的行为和兼容性存在问题,因此被 noexcept 取代。

示例:

void func() noexcept {
    // 保证不抛出异常
}

void test() {
    try {
        func();
    } catch (...) {
        // 永远不会捕获到异常,因为 func 是 noexcept
    }
}

总结来说,noexcept 用来声明和约束函数不抛出异常,有助于提高程序的安全性和性能。

标签:函数,noexcept,explicit,C++,MyClass,隐式,构造函数
From: https://www.cnblogs.com/smartljy/p/18448969

相关文章

  • c++ 键盘/鼠标交互
    c++键盘/鼠标交互鼠标操作点击加上如下宏定义#include<windows.h>#defineKEY_DOWN(VK_NONAME)((GetAsyncKeyState(VK_NONAME)&0x8000)?1:0)#defineKEY_UP(VK_NONAME)((GetAsyncKeyState(VK_NONAME)&0x8000)?0:1)如果获取左键的点击,可以使用如下的代码:KEY_D......
  • c++面经系列0:开篇-c++岗位面试都会问些什么?
    本文是C++岗位面试经验分享系列的开篇,敬请持续关注。在C++岗位面试中,通常首先进行技术面试,若通过则会进行HR面试。HR面试的内容先暂且略过,未来我们会有机会深入探讨,今天我们主要聚焦于技术面试的环节。技术面试通常由同岗位的同事或技术团队的领导担任面试官。在开场交流时,可以......
  • C++ 动态类型转换
    概念在C++中,dynamic_cast是一种运行时类型转换操作符。它主要用于在类的层次结构中进行安全的向下转换(将基类指针或引用转换为派生类指针或引用)。这种转换基于对象的实际类型进行检查,以确保转换的安全性。使用条件为了使用dynamic_cast,类层次结构中必须包含虚函数。这是因......
  • C++ 静态类型转换和动态类型转换的区别
    静态类型转换(static_cast)概念static_cast是C++中的一种类型转换操作符,用于在编译时进行类型转换。它主要用于具有明确的、编译器可以在编译阶段确定的类型转换关系的情况。这种转换通常在相关类型之间进行,例如基本数据类型之间的转换,或者在类层次结构中的向上转换(将派生类指......
  • C++ 重解释类型转换
    概念在C++中,reinterpret_cast被称为重新解释类型转换。它是一种强制类型转换操作符,用于将一种数据类型转换为另一种几乎完全不相关的数据类型。这种转换不进行任何数据的重新格式化或转换操作,只是简单地将数据的二进制表示重新解释为新的类型。语法语法形式为:reinterpret_......
  • C++ 常类型转换
    概念在C++中,常类型转换主要涉及到const_cast操作符,用于在特定情况下对const(常量)限定符进行处理。const关键字在C++中有重要意义,它表示被修饰的对象是常量,不能被修改。但在某些特殊情况下,需要在不破坏常量性语义的前提下,进行与常量相关的操作转换。const_cast的使用示例调......
  • C++ 类型强转
    static_cast基本概念static_cast主要用于在相关类型之间进行转换,这些类型之间存在某种隐式转换关系。它在编译时进行检查,是一种比较安全的类型转换方式。适用场景基本数据类型转换:例如将int转换为double,或者double转换为int(会截断小数部分)。intnumInt=5;doublenumD......
  • C++ 模板详解(一)
    C++模板模板是C++支持参数化多态的工具,使用模板可以使用户为类或者函数声明一种一般模式,使得类中的某些数据成员或者成员函数的参数、返回值取得任意类型。模板是一种对类型进行参数化的工具;通常有两种形式:函数模板和类模板;函数模板针对仅参数类型不同的函......
  • c++之auto关键字的注意点(涉及decltype)
    1.基本规则auto会根据初始化表达式的类型推导出变量的类型。如果初始化的是值类型,auto推导出的也是值类型。如果初始化的是引用类型,auto会忽略引用类型,并推导出被引用对象的类型。如果初始化表达式是常量(const),且auto不是引用类型,推导出的类型会去掉const限定符。vo......
  • 欧拉筛解释(含C++代码)
    intprime[MAXN];//质数列表boolisPrime[MAXN];//标记是否为质数(0表示是,1表示不是)intcnt;//prime表长/*对于任意合数m,可写作m=p*k(p为m的最小质因子,k为m/p,m、k>1且为整数,k>p(p为最小质因子,k为其它几个质因子相乘,每个质因子都比p大,所以k>p))*///欧拉筛(使每个合数......