当前位置: 首页 > news >正文

1.5 新特性 C++面试常见问题

1.5.1 说说C++11的新特性有哪些?

C++11 引入了许多重要的新特性和增强,目的是提升语言的性能、可读性和简洁性。以下是 C++11 的一些主要新特性:

1. 自动类型推导

  • 使用 auto 关键字,可以让编译器自动推导变量的类型。
    auto x = 42;        // int
    auto y = 3.14;     // double
    

2. 范围基的 for 循环

  • 提供了简化的语法来遍历容器。
    std::vector<int> vec = {1, 2, 3, 4, 5};
    for (auto& value : vec) {std::cout << value << " ";
    }
    

3. lambda 表达式

  • 允许定义匿名函数,支持函数式编程。
    auto add = [](int a, int b) { return a + b; };
    std::cout << add(2, 3); // 输出 5
    

4. 智能指针

  • 引入 std::unique_ptr, std::shared_ptr, 和 std::weak_ptr,帮助管理动态内存,避免内存泄漏。
    std::unique_ptr<MyClass> ptr(new MyClass());
    

5. 移动语义

  • 引入右值引用,支持移动构造和移动赋值,提高性能。
    class MyClass {
    public:MyClass(MyClass&& other) noexcept { /* 转移资源 */ }
    };
    

6. 初始化列表

  • 提供了更简洁的对象初始化语法。
    std::vector<int> vec = {1, 2, 3, 4, 5};
    

7. 静态断言

  • 使用 static_assert 在编译时检查条件。
    static_assert(sizeof(int) == 4, "int size must be 4 bytes");
    

8. 线程支持

  • 引入 <thread> 库,提供了线程的创建、管理和同步。
    std::thread t([] { std::cout << "Hello from thread!" << std::endl; });
    t.join();
    

9. 新的标准库组件

  • 增加了 std::chrono 用于时间处理。
  • 增加了 std::random 用于随机数生成。
  • 增加了 std::regex 用于正则表达式匹配。

10. 委托构造函数

  • 允许一个构造函数调用另一个构造函数,以减少重复代码。
    class MyClass {
    public:MyClass() : MyClass(0) {} // 委托构造MyClass(int x) { /* ... */ }
    };
    

11. 显式类型转换

  • 引入 explicit 关键字,以防止不必要的隐式转换。

12. 用户定义的字面量

  • 允许用户定义新的字面量,例如:
    constexpr long double operator"" _km(long double x) { return x * 1000.0; }
    

13. 范围和 nullptr

  • 引入了 nullptr 作为指针的空值,替代 NULL,增加类型安全。

14. 对 const 的增强

  • 引入 constexpr,允许在编译时计算常量。

总结

C++11 是一个重大的版本,添加了许多新的特性,极大地提升了 C++ 的表达能力和性能。通过这些新特性,开发者可以编写更高效、更易读和更安全的代码。

1.5.2 说说C++中智能指针和指针的区别是什么?

智能指针和普通指针在 C++ 中有着显著的区别。智能指针是为了更好地管理动态内存而引入的,它们在某些方面提供了比普通指针更高的安全性和便利性。以下是它们之间的一些主要区别:

1. 内存管理

  • 普通指针

    • 需要手动管理内存,使用 new 分配内存和 delete 释放内存。
    • 容易导致内存泄漏、悬空指针和双重释放等问题。
    int* ptr = new int(10);
    delete ptr; // 手动释放内存
    
  • 智能指针

    • 自动管理内存,确保在不再需要时自动释放内存。
    • 使用 RAII(资源获取即初始化)原则,能够有效避免内存泄漏和悬空指针。
    • 主要有三种类型:std::unique_ptrstd::shared_ptrstd::weak_ptr

2. 类型

  • 普通指针

    • 只是简单的内存地址,表示某个对象的地址。
    • 不提供所有权管理和引用计数功能。
  • 智能指针

    • 是类的实例,封装了指针并提供额外的功能。
    • 具有所有权管理能力,支持引用计数(std::shared_ptr)和独占所有权(std::unique_ptr)。

3. 所有权

  • 普通指针

    • 不支持所有权转移,所有权是模糊的,容易产生不确定性。
  • 智能指针

    • std::unique_ptr 拥有独占所有权,只能有一个智能指针管理同一对象。
    • std::shared_ptr 允许多个指针共享同一个对象的所有权,并通过引用计数管理内存。
    • std::weak_ptr 作为 shared_ptr 的辅助,避免循环引用。

4. 使用简便性

  • 普通指针

    • 在使用上较为直接,但需要小心手动管理内存。
  • 智能指针

    • 提供更安全的 API,允许以更简单的方式处理对象的生命周期。
    • 智能指针的构造和析构都是自动的,用户不需要显式调用 delete

5. 性能

  • 普通指针

    • 通常性能较高,因为没有额外的管理开销。
  • 智能指针

    • std::unique_ptr 的性能开销非常小,接近普通指针。
    • std::shared_ptr 由于需要管理引用计数,可能会引入额外的性能开销。

6. 功能

  • 普通指针

    • 仅能指向对象,没有其他功能。
  • 智能指针

    • 提供了额外的功能,如 std::shared_ptruse_count(),可以查询当前引用计数。

示例

普通指针

int* ptr = new int(10);
// 使用 ptr
delete ptr; // 手动释放

智能指针

#include <memory>std::unique_ptr<int> uptr(new int(10)); // 使用 unique_ptr
// 不需要手动 delete,uptr 超出作用域时会自动释放内存std::shared_ptr<int> sptr = std::make_shared<int>(20); // 使用 shared_ptr
// 内存会在没有引用时自动释放

总结

智能指针在内存管理上提供了更高的安全性和便利性,能够有效避免许多常见的内存管理错误,而普通指针则需要开发者自行管理内存。使用智能指针可以减少内存泄漏和其他潜在问题,使代码更加健壮。

1.5.3 说说C++中的智能指针有哪些?分别解决的问题以及区别?

C++ 中主要有三种智能指针:std::unique_ptrstd::shared_ptrstd::weak_ptr。它们各自解决特定的问题,并在内存管理中提供不同的功能和特性。以下是它们的详细介绍、解决的问题以及区别:

1. std::unique_ptr

特点
  • 独占所有权std::unique_ptr 拥有指向对象的唯一所有权,不能被复制。
  • 自动释放:当 std::unique_ptr 超出作用域时,自动调用 delete 释放内存。
  • 支持移动语义:可以通过移动构造和移动赋值将所有权转移给另一个 unique_ptr
解决的问题
  • 避免内存泄漏:自动管理内存,确保内存被释放。
  • 简化代码:无需手动调用 delete,避免了常见的内存管理错误。
示例
#include <memory>std::unique_ptr<int> uptr(new int(10)); // 创建 unique_ptr
// 不需要手动 delete,uptr 超出作用域时会自动释放内存

2. std::shared_ptr

特点
  • 共享所有权:多个 std::shared_ptr 可以指向同一个对象,使用引用计数管理所有权。
  • 引用计数:当最后一个指向对象的 shared_ptr 被销毁时,自动释放对象内存。
  • 线程安全:对引用计数的操作是线程安全的,但对对象本身的访问需要额外的同步。
解决的问题
  • 避免内存泄漏:通过引用计数确保对象在没有指针指向时被释放。
  • 多个所有者:支持多个指针共享同一对象,方便实现共享资源。
示例
#include <memory>std::shared_ptr<int> sptr1 = std::make_shared<int>(20); // 创建 shared_ptr
std::shared_ptr<int> sptr2 = sptr1; // sptr2 共享 sptr1 的所有权
// 当 sptr1 和 sptr2 超出作用域时,内存将自动释放

3. std::weak_ptr

特点
  • 不拥有所有权std::weak_ptr 不拥有对象的所有权,只是观察 shared_ptr 指向的对象。
  • 防止循环引用:通过不增加引用计数来避免循环引用问题。
  • 临时访问:可以通过 std::shared_ptr 来访问对象,但不会影响引用计数。
解决的问题
  • 避免循环引用:在使用 shared_ptr 的情况下,防止造成内存泄漏。
  • 检查对象有效性:可以检查指向的对象是否仍然存在。
示例
#include <memory>std::shared_ptr<int> sptr = std::make_shared<int>(30);
std::weak_ptr<int> wptr = sptr; // 创建 weak_ptrif (auto temp = wptr.lock()) { // 尝试获取 shared_ptrstd::cout << *temp; // 使用 temp
} else {std::cout << "对象已被释放";
}

区别总结

特性std::unique_ptrstd::shared_ptrstd::weak_ptr
所有权独占所有权共享所有权不拥有所有权
拷贝与移动不可拷贝,只能移动可拷贝,支持引用计数不可拷贝,通常与 shared_ptr 一起使用
引用计数
内存管理自动释放自动释放,当最后一个 shared_ptr 被销毁时不管理内存,提供对 shared_ptr 的观察
用途适合唯一拥有者场景适合多个所有者场景适合避免循环引用和临时访问对象

总结

C++ 的智能指针提供了高效、安全的内存管理机制,帮助开发者避免常见的内存管理错误。选择合适的智能指针类型,可以根据具体的需求和使用场景来有效管理资源,确保代码的健壮性和安全性。

1.5.4 简述 C++ 右值引用与转移语义

C++ 中的 右值引用rvalue references)和 转移语义move semantics)是 C++11 引入的两个关键特性,旨在提高程序性能,特别是处理临时对象和大型数据结构时。

右值引用

  • 右值引用 使用 && 表示,仅能绑定到右值(例如临时对象或字面值)上。
  • 它允许对临时对象进行“窃取”操作,避免不必要的深拷贝。

示例

int&& r = 10;  // r 是一个右值引用,绑定到右值 10 上

转移语义

  • 转移语义 是利用右值引用来实现资源的“转移”而非复制,从而避免性能开销。
  • 转移语义主要通过移动构造函数移动赋值运算符实现,使得资源可以从一个对象转移到另一个对象。

示例

std::vector<int> a = {1, 2, 3};
std::vector<int> b = std::move(a);  // 将 a 的资源转移到 b 中

作用和意义

  • 避免不必要的拷贝:特别是处理临时对象或返回大对象时,转移语义避免了深拷贝。
  • 提升性能:在容器操作和资源管理中,通过转移语义减少了开销。

总结

右值引用和转移语义在 C++ 中提供了高效的资源管理方式,尤其在处理大数据时,能显著提升程序的执行效率。

1.5.5 简述C++中智能指针的特点

C++ 中的智能指针(smart pointers)是 C++11 引入的一种内存管理工具,通过 RAII(资源获取即初始化)原则管理动态内存,自动释放资源,避免内存泄漏和管理错误。常见的智能指针有 std::unique_ptrstd::shared_ptrstd::weak_ptr。以下是它们的特点:

1. std::unique_ptr

  • 特点:独占所有权,一个对象只能由一个 unique_ptr 管理,不能复制,只能转移。
  • 适用场景:唯一所有权,确保对象只被一个指针管理,如函数内部的临时对象。
  • 实现:提供了移动构造和移动赋值函数。

2. std::shared_ptr

  • 特点:共享所有权,可以有多个 shared_ptr 指向同一对象,引用计数管理对象生命周期。
  • 适用场景:多个指针共享同一资源,适用于对象需要多个所有者的情况。
  • 实现:引用计数机制确保最后一个 shared_ptr 销毁时自动释放资源。

3. std::weak_ptr

  • 特点:不拥有对象的所有权,与 shared_ptr 协作,避免循环引用。
  • 适用场景:用于观察对象生命周期,防止循环引用导致的内存泄漏。
  • 实现:没有增加引用计数的轻量级指针,通过 lock() 函数临时访问资源。

智能指针的通用特点

  • 自动内存管理:在超出作用域时自动释放资源,无需手动调用 delete
  • 安全性:通过封装原生指针,减少悬空指针、重复释放等内存管理错误。
  • 便捷性:提供了简单的接口,适应 C++ RAII 原则,降低手动内存管理的复杂度。

总结

智能指针通过自动化的资源管理提高了代码的安全性和健壮性,适合用于现代 C++ 的资源管理和内存控制。

1.5.6 weak_ptr 能不能知道对象计数为0,为什么?

总结

  • weak_ptr 无法直接访问对象的引用计数。
  • 可以通过 lock() 判断对象是否存在,但无法获得确切的引用计数。

std::weak_ptr 不能直接知道对象的引用计数是否为 0。这是因为 weak_ptr 本身不影响 shared_ptr 的引用计数,它只是一个对所指对象的非拥有性弱引用。虽然 weak_ptr 会跟踪对象的生命周期,但它无法直接查看或影响 shared_ptr 的引用计数。

原因

  1. 引用计数独立性weak_ptrshared_ptr 引用计数独立存在。shared_ptr 持有两个计数器:一个是共享引用计数(用于跟踪 shared_ptr 的数量),另一个是弱引用计数(用于跟踪 weak_ptr 的数量)。weak_ptr 增加的是弱引用计数,而非共享引用计数。

  2. 访问方法限制weak_ptr 可以通过 lock() 方法临时转换为 shared_ptr,然后检查对象是否有效(即 shared_ptr 是否为 nullptr)。但 weak_ptr 不能直接查看 shared_ptr 的引用计数。

如何检查对象是否已销毁

可以通过 weak_ptrlock() 方法来判断:

  • 如果 lock() 返回一个空的 shared_ptr(即 nullptr),说明对象已经被销毁,引用计数为 0。
  • 如果 lock() 返回一个非空 shared_ptr,则对象仍然存在。

示例

#include <iostream>
#include <memory>std::weak_ptr<int> wptr;{auto sptr = std::make_shared<int>(10);wptr = sptr;std::cout << "Shared count: " << sptr.use_count() << std::endl;  // 输出引用计数
}if (auto temp = wptr.lock()) {std::cout << "对象仍然存在。" << std::endl;
} else {std::cout << "对象已被销毁,引用计数为 0。" << std::endl;
}

1.5.7 weak_ptr 如何解决 shared_ptr 的循环引用问题?

std::weak_ptr 通过不增加引用计数来解决 shared_ptr 的循环引用问题。当两个对象相互持有 shared_ptr 时,它们的引用计数永远不会减少到零,导致资源无法释放,从而引发内存泄漏。使用 weak_ptr 可以打破这个循环。

问题背景

假设两个类 AB 各自拥有一个 shared_ptr 指向对方的实例,形成了循环引用:

class B; // 前向声明class A {
public:std::shared_ptr<B> b_ptr;
};class B {
public:std::shared_ptr<A> a_ptr;
};

在这种情况下,即使超出作用域后 ABshared_ptr 都销毁了,但由于两者互相引用,shared_ptr 的引用计数不会归零,导致两者的资源都无法释放。

使用 weak_ptr 打破循环引用

为了防止循环引用,可以将其中一个类的 shared_ptr 改为 weak_ptr,使其不参与引用计数,从而允许资源在不再使用时正确释放。例如,将 B 中的指针改为 weak_ptr

#include <memory>class B; // 前向声明class A {
public:std::shared_ptr<B> b_ptr; // 正常的 shared_ptr,拥有 B 的所有权~A() { std::cout << "A destroyed\n"; }
};class B {
public:std::weak_ptr<A> a_ptr; // 使用 weak_ptr 打破循环引用~B() { std::cout << "B destroyed\n"; }
};int main() {auto a = std::make_shared<A>();auto b = std::make_shared<B>();a->b_ptr = b;b->a_ptr = a; // B 对 A 的引用不会增加 A 的引用计数// 当 main 函数结束时,a 和 b 会自动销毁,调用析构函数
}

工作原理

  • A 拥有 Bshared_ptr,因此 B 的引用计数增加。
  • B 使用 weak_ptr 指向 A,不增加 A 的引用计数。
  • main 函数结束时,shared_ptr 计数归零,资源顺利释放。

总结

通过使用 weak_ptr,可以避免 shared_ptr 之间相互引用时的内存泄漏问题,确保资源按预期被释放。

1.5.8 shared_ptr怎么知道跟他共享对象的指针释放了?

std::shared_ptr 通过引用计数来跟踪对象的生命周期,确保共享的对象在没有任何 shared_ptr 指向它时才会释放。当所有指向该对象的 shared_ptr 实例被销毁后,对象才会自动释放。

工作机制

  1. 引用计数:每个 shared_ptr 在指向某对象时,内部会维护一个引用计数use_count),用来记录指向该对象的 shared_ptr 数量。shared_ptr 的构造、复制或赋值会增加引用计数,而析构、重置或释放会减少引用计数。

  2. 自动释放:当 use_count 归零,即没有 shared_ptr 实例再指向该对象时,shared_ptr 会自动销毁托管的对象,并释放相关资源。

例子

#include <iostream>
#include <memory>int main() {std::shared_ptr<int> ptr1 = std::make_shared<int>(10);std::cout << "Use count after ptr1: " << ptr1.use_count() << std::endl; // 输出 1{std::shared_ptr<int> ptr2 = ptr1; // 引用计数 +1std::coutshared_ << "Use count after ptr2: " << ptr1.use_count() << std::endl; // 输出 2} // 离开作用域,ptr2 被销毁,引用计数 -1std::cout << "Use count after ptr2 out of scope: " << ptr1.use_count() << std::endl; // 输出 1return 0;
} // 离开作用域,ptr1 被销毁,引用计数变为 0,对象自动释放

总结

shared_ptr 通过引用计数来监控共享对象的状态,只有在引用计数为 0 时才会释放对象,因此任何一个 shared_ptr 不需要主动跟踪其他 shared_ptr 的销毁状态。

1.5.9 说说智能指针及其实现,shared_ptr 线程安全性,原理

智能指针是 C++11 引入的自动化内存管理工具,用于管理动态分配的资源,防止内存泄漏。常见的智能指针包括 std::unique_ptrstd::shared_ptrstd::weak_ptr。它们依赖 RAII(资源获取即初始化)原则来控制对象的生命周期,确保资源在不再需要时被自动释放。智能指针主要通过引用计数、所有权转移、弱引用等机制来实现。

智能指针的实现

  1. std::unique_ptr

    • 实现:仅有单一所有权,一个对象只能被一个 unique_ptr 实例持有。转移所有权时通过移动语义(move)转移资源。
    • 使用场景:适用于只需单一拥有者的对象,不允许共享,不可复制,只能移动。
    • 线程安全性:不支持多线程访问,不能多线程共享同一个 unique_ptr,因为它独占资源。
  2. std::shared_ptr

    • 实现:通过共享所有权管理资源。每个 shared_ptr 都持有一个指向共享控制块的指针,该控制块中包含引用计数,跟踪资源的共享情况。当引用计数归零时释放资源。
    • 使用场景:适合需要多个指针共同持有同一对象的情况,比如在图、树等数据结构中。
  3. std::weak_ptr

    • 实现:用于解决循环引用问题。weak_ptr 仅作为对 shared_ptr 所指对象的弱引用,不增加引用计数,但可以检查对象是否存在。
    • 使用场景:用于临时观察对象生命周期,避免循环引用,比如双向关联的数据结构。

shared_ptr 的线程安全性

C++ 标准对 shared_ptr 提供了基本的线程安全保证,主要体现在引用计数更新的原子性上。

  • 线程安全的引用计数shared_ptr 使用了原子操作(std::atomic)来管理引用计数的增加和减少,因此多个线程可以安全地复制和销毁 shared_ptr。这意味着,即便多个线程同时持有同一 shared_ptr 实例的副本,也可以保证引用计数的正确性,确保资源在引用计数归零后才会释放。

  • 指针的线程安全性:虽然 shared_ptr 对引用计数的操作是线程安全的,但对于托管的资源本身或 shared_ptr 的数据成员并不提供线程安全保护。如果多个线程需要同时访问或修改托管对象的数据,仍需手动添加同步措施(如使用 mutex),以确保数据安全。

shared_ptr 的实现原理

  1. 控制块(Control Block)
    shared_ptr 内部会创建一个控制块(control block),其中包含:

    • 引用计数(use count):跟踪当前有多少 shared_ptr 指向同一对象。
    • 弱引用计数(weak count):跟踪当前有多少 weak_ptr 指向同一对象。
    • 托管对象的指针:指向实际管理的资源。

    shared_ptr 被复制时,use count 增加;当 shared_ptr 被销毁时,use count 减少。use count 归零时,托管对象销毁,而当 weak count 也为零时,控制块也会销毁。

  2. 引用计数的原子操作
    为了保证引用计数操作的线程安全性,shared_ptr 使用了原子操作来增加和减少引用计数。这使得多个 shared_ptr 实例可以安全地在多线程环境中操作同一对象的引用计数,而不会出现计数不一致的情况。

总结

智能指针通过引用计数、独占所有权和弱引用等机制来有效管理资源。shared_ptr 通过原子化引用计数实现了基本的线程安全,确保多线程中共享的对象在最后一个 shared_ptr 销毁后才释放资源。

1.5.10 请回答智能指针有没有内存泄漏的情况?

智能指针是C++11引入的一个功能,用于自动管理动态分配的内存,减少内存泄漏的风险。常见的智能指针包括 std::unique_ptrstd::shared_ptrstd::weak_ptr。然而,智能指针并不能完全消除内存泄漏,以下是一些可能导致内存泄漏的情况:

1. 循环引用

  • 情况:当两个或多个 std::shared_ptr 互相引用时,可能导致循环引用。由于引用计数无法减少到零,内存无法释放。
  • 解决方案:使用 std::weak_ptr 来打破循环引用。

2. 不当使用 newdelete

  • 情况:如果手动分配内存(使用 new)而不使用智能指针,或者在智能指针的管理范围外使用 delete,可能会导致内存泄漏。
  • 解决方案:确保始终通过智能指针管理动态分配的内存。

3. 被忽略的异常

  • 情况:如果在使用智能指针的过程中抛出异常,某些资源可能没有被正确释放,导致内存泄漏。
  • 解决方案:使用 RAII(资源获取即初始化)原则,确保资源在异常情况下也能正确释放。

4. 使用不当

  • 情况:如果将智能指针的所有权错误地转移或丢失,可能导致内存泄漏。例如,将 std::unique_ptr 传递到函数时,如果没有正确地转移所有权,原有的智能指针仍会保留对内存的引用。
  • 解决方案:使用 std::move 进行所有权转移,确保智能指针的生命周期和所有权管理是清晰的。

总结

尽管智能指针大大减少了内存泄漏的可能性,但在使用它们时仍需谨慎,确保遵循最佳实践来避免潜在的内存管理问题。

1.5.11 简述C++11的四种类型转换

C++11引入了四种主要的类型转换运算符,它们分别是:

1. static_cast

  • 用途:用于进行类型安全的转换,可以在相关类型之间进行转换,例如:
    • 基类指针到派生类指针(需要保证安全)。
    • 基本数据类型之间的转换(如 intfloat)。
  • 特征
    • 在编译时进行类型检查。
    • 不会进行运行时类型检查。

2. dynamic_cast

  • 用途:用于进行安全的向下转型(从基类到派生类),适用于多态类型(即具有虚函数的类)。
  • 特征
    • 在运行时进行类型检查。
    • 如果转换不成功,返回 nullptr(对于指针类型)或抛出 std::bad_cast 异常(对于引用类型)。

3. const_cast

  • 用途:用于添加或移除类型的 constvolatile 限定符。
  • 特征
    • 允许修改常量对象的值(需谨慎使用)。
    • 主要用于在需要修改 const 对象时的场景,但需要确保对象的原始类型允许修改。

4. reinterpret_cast

  • 用途:用于在任意类型之间进行低级别的位级别转换。
  • 特征
    • 不进行任何类型检查,可能导致不安全的转换。
    • 通常用于操作底层数据结构、指针类型之间的转换等。

总结表

转换类型用途特点
static_cast类型安全的转换编译时检查,不安全的转换可导致未定义行为
dynamic_cast多态类型间的安全向下转型运行时检查,失败返回 nullptr
const_cast添加或移除 const 限定符允许修改常量对象
reinterpret_cast任意类型之间的低级别位级别转换不安全,几乎不进行检查

这些类型转换运算符使得C++的类型系统更加灵活和强大,开发者可以根据需求选择合适的转换方式。

1.5.12 简述C++11中的auto的具体用法

C++11引入了 auto 关键字,允许编译器根据初始化表达式自动推导变量的类型。这使得代码更加简洁和易读,尤其是在处理复杂类型时。以下是 auto 的具体用法和一些注意事项:

1. 基本用法

  • 声明变量:使用 auto 声明变量时,编译器会根据右侧的表达式推导出变量的类型。
    auto x = 10;           // x 是 int 类型
    auto y = 3.14;        // y 是 double 类型
    auto str = "Hello";   // str 是 const char* 类型
    

2. 与 STL 容器配合使用

  • 迭代器:在使用标准模板库(STL)时,auto 可以简化迭代器的声明。
    std::vector<int> vec = {1, 2, 3};
    for (auto it = vec.begin(); it != vec.end(); ++it) {std::cout << *it << " ";
    }
    

3. Lambda 表达式

  • 使用 auto 作为参数类型:在 lambda 表达式中,auto 可以用于参数类型推导。
    auto lambda = [](auto a, auto b) {return a + b; // a 和 b 的类型由调用时推导
    };
    

4. 多重类型推导

  • 结构化绑定:C++17引入的结构化绑定特性与 auto 结合,可以同时推导多个变量的类型。
    std::tuple<int, double> tup = {1, 2.5};
    auto [a, b] = tup; // a 是 int,b 是 double
    

5. 注意事项

  • 不能用于声明函数返回类型auto 不能单独用于函数的返回类型,但可以通过尾返回类型语法实现。

    auto func() -> int {return 42;
    }
    
  • 推导规则auto 不能用于没有初始化的变量声明,因为没有类型推导的上下文。

    auto z; // 错误:缺少初始化
    

总结

使用 auto 关键字可以提高代码的可读性和简洁性,尤其在处理复杂类型时(如容器、迭代器和lambda)。但使用时应注意类型推导的规则,确保代码的可维护性和可理解性。

1.5.13 简述一下C++11 中的可变参数模板新特性

C++11引入了可变参数模板(Variadic Templates),使得模板可以接收可变数量的参数。这一特性极大地增强了模板编程的灵活性,支持更为通用的代码结构。以下是可变参数模板的一些关键点和用法:

1. 基本语法

可变参数模板的定义使用 template<typename... Args>,其中 Args 是一个类型参数包,可以接收任意数量的类型。

template<typename... Args>
void func(Args... args) {// 函数体
}

2. 参数展开

在函数内部,可以使用参数展开(parameter pack expansion)来处理这些参数。

#include <iostream>template<typename... Args>
void print(Args... args) {(std::cout << ... << args) << std::endl; // 使用折叠表达式(C++17)
}int main() {print(1, 2.5, "Hello"); // 输出: 1 2.5 Hello
}

3. 递归模板

可以通过递归的方式处理参数包,实现如计算参数个数、拼接字符串等功能。

template<typename T>
void printOne(T t) {std::cout << t << " ";
}template<typename T, typename... Args>
void printOne(T t, Args... args) {std::cout << t << " ";printOne(args...); // 递归处理剩余参数
}

4. 结合其他特性

可变参数模板可以与其他C++特性(如 decltype、类型萃取、特化等)结合使用,以实现更复杂的功能。

5. 示例:参数数量计算

使用可变参数模板可以轻松实现参数数量的计算。

template<typename... Args>
struct Count;template<typename T, typename... Args>
struct Count<T, Args...> {static const int value = 1 + Count<Args...>::value; // 递归计算
};template<>
struct Count<> {static const int value = 0; // 基础情况
};// 用法
std::cout << Count<int, double, char>::value; // 输出: 3

6. 使用场景

可变参数模板适用于需要处理不确定数量参数的场景,如:

  • 实现类似于 printf 的函数。
  • 在库函数中处理任意数量的输入。
  • 生成特定类型的复合类型。

总结

可变参数模板是C++11的重要特性,它提供了更大的灵活性和扩展性,简化了处理多个参数的代码。通过参数展开和递归,开发者可以方便地构建复杂的模板功能。

1.5.14 简述C++中的Lambda新特性

C++11引入了Lambda表达式,使得可以在代码中定义匿名函数。Lambda表达式极大地提高了代码的简洁性和可读性,特别是在需要临时函数的场景中。以下是C++中的Lambda表达式的一些关键特性和用法:

1. 基本语法

Lambda表达式的基本语法如下:

[capture](parameters) -> return_type {// 函数体
}
  • capture:捕获外部变量的方式。
  • parameters:参数列表,可以为空。
  • return_type:可选,返回类型。
  • 函数体:实际的函数实现。

2. 捕获外部变量

Lambda可以捕获外部作用域的变量,有多种捕获方式:

  • 值捕获[x]):复制外部变量 x 的值。
  • 引用捕获[&x]):引用外部变量 x
  • 全局捕获[=]):以值捕获所有外部变量。
  • 全局引用捕获[&]):以引用捕获所有外部变量。
int x = 10;
auto lambda = [x]() { return x + 1; }; // 捕获 x 的值
std::cout << lambda(); // 输出: 11auto lambda_ref = [&x]() { x++; }; // 捕获 x 的引用
lambda_ref();
std::cout << x; // 输出: 11

3. 使用场景

  • 作为参数传递:Lambda可以作为参数传递给标准库算法,如 std::sortstd::for_each 等。
std::vector<int> vec = {1, 2, 3, 4, 5};
std::for_each(vec.begin(), vec.end(), [](int n) { std::cout << n << " "; });
  • 简化代码:Lambda可以替代临时函数或函数对象,减少冗余代码。

4. 返回类型推导

C++14引入了自动返回类型推导,允许省略返回类型:

auto lambda = [](int a, int b) { return a + b; }; // 自动推导返回类型为 int

5. 递归Lambda

C++14支持递归Lambda,通过 std::function 或者 [] 捕获自身。

std::function<int(int)> factorial = [&](int n) {return (n <= 1) ? 1 : n * factorial(n - 1);
};
std::cout << factorial(5); // 输出: 120

6. 注意事项

  • 生命周期:Lambda捕获的外部变量在Lambda使用时必须是有效的。
  • 类型:Lambda表达式的类型是唯一的,因此不能直接传递给需要具体类型的接口。

总结

Lambda表达式是C++11的重要特性,提供了简洁的语法来定义匿名函数,支持捕获外部变量,极大地增强了代码的可读性和可维护性。通过灵活的捕获机制和简化的函数定义,Lambda使得现代C++编程更加高效和灵活。

相关文章:

1.5 新特性 C++面试常见问题

1.5.1 说说C11的新特性有哪些&#xff1f; C11 引入了许多重要的新特性和增强&#xff0c;目的是提升语言的性能、可读性和简洁性。以下是 C11 的一些主要新特性&#xff1a; 1. 自动类型推导 使用 auto 关键字&#xff0c;可以让编译器自动推导变量的类型。auto x 42; …...

[mysql]子查询的概述和分类及单行子查询

子查询引入 查询的基本结构已经给大家了,子查询里面也是有一些新的内容,子查询其实就是在查询中嵌套另一个查询,叫嵌套查询可能大家更容易理解一点..,类似与FOR循环和FOR循环的嵌套,这一章是我们查询的最难的部分,大家 难度是查询的顶峰,多表查询和子查询是非常重要,SQL优化里…...

SpringMVC执行流程(视图阶段JSP、前后端分离阶段)、面试题

目录 1.SpringMVC执行流程分为以下两种 2.非前后端分离的SpringMVC的执行流程 3.前后端分离的项目SpringMVC执行流程 4. 面试题 1.SpringMVC执行流程分为以下两种 2.非前后端分离的SpringMVC的执行流程 流程图&#xff1a; 更加生动的描述&#xff1a; DisPatcherServlet…...

宠物空气净化器有用吗?有哪几款吸毛效果好且低噪的推荐

伴随着天气越来越凉&#xff0c;照常来说&#xff0c;猫咪掉毛的频率应该会变少&#xff0c;但是为什么我家的猫咪还在掉很多毛。 现在就连南方地区都要加外套了&#xff0c;但是猫咪掉毛太多&#xff0c;都不敢穿纯棉面料的衣服&#xff0c;还有本来想着顺应天气的变化&#…...

linux -磁盘管理命令

学会用fidsk -l blkid lskid 就够用 格式化文件系统&#xff1a;mkfs -t <文件系统格式> /dev/vdb1 1..df -Th 查看磁盘挂载情况。 2.fdisk 磁盘分区命令 示例一&#xff1a;fdisk -l 查看磁盘分区&#xff0c;箭头指出分区信息 示例二&#xff1a;创建分区eg…...

[Chrome插件开发]关于报错Service worker registration failed. Status code: 15

manifest.json中不能使用ts&#xff1a; "background": {"service_worker": "background.ts"}只能使用js "background": {"service_worker": "background.js"}在vite.config.js中增加以下配置&#xff0c;可以将…...

uniapp封装movable-area+movable-view组件,实现悬浮按钮可拖动,自动吸附边缘效果,自动向两边靠拢

兼容H5、App、微信小程序 子组件 /components/ShopCar/ShopCar.vue <template><view class"ShopCar"><movable-area class"movableArea" v-if"isShow"><movable-view class"movableView" :position"posi…...

音频重采样(libresample)

https://github.com/minorninth/libresample USB audio同步问题及Jitter分析_usb mic i2s 时钟不同步-CSDN博客 是的&#xff0c;电脑和 USB 摄像头之间的 UAC&#xff08;USB Audio Class&#xff09;传输&#xff0c;**可能会因为两边时钟不同步而引起破音问题**。时钟不同…...

使用Python来下一场雪

具体效果&#xff1a;&#xff08;大雪缓缓下落&#xff09; 完整代码&#xff1a; import pygame import random# 初始化 Pygame pygame.init()# 设置窗口 width, height 800, 600 screen pygame.display.set_mode((width, height)) pygame.display.set_caption("下雪…...

Pyspark中pyspark.sql.functions常用方法(4)

文章目录 pyspark sql functionsforall 判断array是否满足allfilter 过滤zip_with 数组合并 pyspark sql functions forall 判断array是否满足all df spark.createDataFrame([(1, ["bar"]), (2, ["foo", "bar"]), (3, ["foobar", &…...

Nginx 配置基于IP 地址的 Web 服务器

Nginx 配置基于IP 地址的 Web 服务器 1.配置网卡 nmcli connection modify ipv4.address 192.168.232.130/24 ipv4.gateway 192.168.232.2 ipv4.dns 192.168.232.2 ipv4.method manual connection.autoconnect yes 2.添加ip地址 nmcli connection modify ens160 ipv4.address…...

【TVM 教程】线性和递归核

Apache TVM 是一个端到端的深度学习编译框架&#xff0c;适用于 CPU、GPU 和各种机器学习加速芯片。更多 TVM 中文文档可访问 → https://tvm.hyper.ai/ 作者&#xff1a;Tianqi Chen 下面介绍如何在 TVM 中进行递归计算&#xff08;神经网络中的典型模式&#xff09;。 from…...

猫主福利大放送,双11猫奴们的购物狂欢节 养猫必备清单

双十一购物狂欢节终于来啦&#xff01;铲屎官们是不是已经迫不及待想为心爱的猫咪挑选新玩具和必需品了呢&#xff1f;作为一名资深铲屎官&#xff0c;我专门为大家整理了一份双十一养猫必备清单。抓住这个难得的机会&#xff0c;让我们为猫咪挑选最舒适、最实用的好物吧&#…...

Linux中gcc的使用

GCC的基本概念和用途 GCC&#xff08;GNU Compiler Collection&#xff09;是GNU项目提供的一套编程语言编译器集合&#xff0c;包括了C、C、Objective-C、Fortran、Java、Ada和Go等语言的编译器。GCC广泛用于Linux和其他类Unix系统中&#xff0c;用于将源代码编译成可执行文件…...

React 组件 API

React 组件 API React 组件 API 是 React 应用程序开发中的核心部分&#xff0c;它提供了一系列的接口和方法&#xff0c;使得开发者能够创建和管理组件的状态、属性以及生命周期。在本篇文章中&#xff0c;我们将深入探讨 React 组件 API 的各个方面&#xff0c;包括组件的定…...

一个使用接口模式、工厂模式、模板方法模式的日志文件系统

引言&#xff1a; 编写一个与具体业务无关的示例代码。这个示例代码主要体现以下几个设计思想和模式&#xff1a; 接口模式&#xff08;Interface Pattern&#xff09;&#xff1a;定义接口类&#xff0c;并让具体实现类去实现该接口的功能。 工厂模式&#xff08;Factory Pa…...

openjdk17 C++源码是怎么给java字段赋值的

##java源码 public class OtherClass {public static int CONSTANT_O9876;public int o1234;public void dddd(){String dddd "dddd";//System.out.println(dddd);System.out.println(ddddCONSTANT_O);}} public int o1234; 在openjdk17中 C源码怎么执行这段代码…...

C++初阶(八)--内存管理

目录 引入&#xff1a; 一、C中的内存布局 1.内存区域 2.示例变量存储位置说明 二、C语言中动态内存管理 三、C内存管理方式 1.new/delete操作内置类型 2.new和delete操作自定义类型 四、operator new与operator delete函数&#xff08;重要点进行讲解&#xff09; …...

C# 企业微信机器人推送消息 windows服务应用程序的使用

C# 企业微信机器人推送消息 先添加一个机器人! 然后查看机器人就可以得到一个 webhook 特别特别要注意&#xff1a;一定要保护好机器人的webhook地址&#xff0c;避免泄漏&#xff01; 然后开始写代码 &#xff0c;只需要httpPost 调用一下这个地址就可以发送消息了。 首先我…...

社区交流系统设计与实现

社区交流系统设计与实现 1. 系统概述 社区交流系统是一个基于PHP和SQL的Web应用程序&#xff0c;旨在为用户提供一个互动交流的平台。该系统允许用户注册、发布帖子、回复帖子、查看其他用户的帖子和回复&#xff0c;以及管理个人资料&#xff0c;提高用户之间的互动和信息共享…...

【模型学习之路】手写+分析bert

手写分析bert 目录 前言 架构 embeddings Bertmodel 预训练任务 MLM NSP Bert 后话 netron可视化 code2flow可视化 fine tuning 前言 Attention is all you need! 读本文前&#xff0c;建议至少看懂【模型学习之路】手写分析Transformer-CSDN博客。 毕竟Bert是tr…...

Redis学习文档(常见面试题)

目录 Redis回收使用的是什么算法&#xff1f; Redis如何做大量数据插入&#xff1f; 为什么要做Redis分区&#xff1f; 你知道有哪些Redis分区实现方案&#xff1f; Redis分区有什么缺点&#xff1f; Redis持久化数据和缓存怎么做扩容&#xff1f; 分布式Redis是前期做还…...

【C++刷题】力扣-#594-最长和谐子序列

题目描述 和谐数组是指一个数组里元素的最大值和最小值之间的差别 正好是 1 。 给你一个整数数组 nums &#xff0c;请你在所有可能的子序列中找到最长的和谐子序列的长度。 数组的 子序列是一个由数组派生出来的序列&#xff0c;它可以通过删除一些元素或不删除元素、且不改变…...

MoveIt 控制自己的真实机械臂【2】——编写 action server 端代码

完成了 MoveIt 这边 action client 的基本配置&#xff0c;MoveIt 理论上可以将规划好的 trajectory 以 action 的形式发布出来了&#xff0c;浅浅尝试一下&#xff0c;在 terminal 中运行 roslaunch xmate7_moveit_config_new demo.launch 报错提示他在等待 xmate_arm_control…...

C#制作学生管理系统

定义学生类 定义一个简单的类来表示学生&#xff0c;包括学号、姓名、性别、年龄、电话、地址。再给其添加一个方法利于后续添加方法查看学生信息。 //定义学生类 public class student {public int ID { get; set; }//开放读写权限public string Name { get; set; }public i…...

python Pandas合并(单元格、sheet、excel )

安装 Pandas 和 openpyxl 首先&#xff0c;确保已经安装了 Pandas 和 openpyxl。可以通过 pip 安装&#xff1a; pip install pandas openpyxl 创建 DataFrame import pandas as pd # 创建 DataFrame df1 pd.DataFrame({ 姓名: [张三, 李四, 王五], 年龄: [25, 30, 35]…...

OJ在线编程常见输入输出练习【JavaScript】

&#xff08;注&#xff1a;本文是对【JavaScript Node 】 ACM模式&#xff0c;常见输入输出练习相关内容的介绍&#xff01;&#xff01;&#xff01;&#xff09; 牛客竞赛_ACM/NOI/CSP/CCPC/ICPC算法编程高难度练习赛_牛客竞赛OJ 一、ACM模式下的编辑页面 二、ACM模式下&a…...

新能源汽车空调系统:绿色出行的舒适保障

在新能源汽车迅速发展的今天&#xff0c;空调系统作为提升驾乘舒适度的重要组成部分&#xff0c;发挥着不可或缺的作用。新能源汽车空调系统主要由压缩机、冷凝器、节流装置和蒸发器四大件组成&#xff0c;它们协同工作&#xff0c;为车内提供适宜的温度和湿度环境。 一、压缩…...

Date工具类详细汇总-Date日期相关方法

# 1024程序员节 | 征文 # 目录 简介 Date工具类单元测试 Date工具类 简介 本文章是个人总结实际工作中常用到的Date工具类&#xff0c;主要包含Java-jdk8以下版本的Date相关使用方法&#xff0c;可以方便的在工作中灵活的应用&#xff0c;在个人工作期间频繁使用这些时间的格…...

TMUX1308PWR规格书 数据手册 具有注入电流控制功能的 5V 双向 8:1单通道和 4:1 双通道多路复用器芯片

TMUX1308 和 TMUX1309 为通用互补金属氧化物半导体 (CMOS) 多路复用器 (MUX)。TMUX1308 是 8:1单通道&#xff08;单端&#xff09;多路复用器&#xff0c;而 TMUX1309 是 4:1 双通道&#xff08;差分&#xff09;多路复用器。这些器件可在源极 (Sx) 和漏极 (Dx) 引脚上支持从 …...

汉阳网站建设鄂icp/厦门百度代理公司

&#x1f4da; 本项目为从零开始学 Web 前端系列图文教程。从零基础开始&#xff0c;手把手教你进入前端开发的世界。从入门到进阶&#xff0c;我们一同前行。 项目背景 大家好&#xff0c;我是前端队长Daotin&#xff0c;想要获取更多前端精彩内容&#xff0c;关注我(全网同…...

哪里有做网站企业/网店推广的方式

返回&#xff1a;贺老师课程教学链接 画出实现下面求解任务的流程图 1、简单循环的流程图&#xff08;提示&#xff1a;m是一个变量&#xff0c;在程序中输入&#xff09;&#xff08;1&#xff09;求1到m的倒数和&#xff0c;即  &#xff08;2&#xff09;求1到m的平方和&…...

廊坊开发区规划建设局网站/1000个关键词

做一件事&#xff0c;如果觉得难那就对了。容易达成的事&#xff0c;没有经过努力获取到的是没有成就感的。人生就像上坡&#xff0c;更高处的风景更值得期待。中国人民大学与加拿大女王大学金融硕士项目给予你前行的力量。 我们每个人的一生中&#xff0c;都是在不断攀登一座…...

网站建设经营范围/谷歌网页版入口

更多实例例子 1移除字符串两侧的空格&#xff1a;$str " Hello World! ";echo "不使用 trim: " . $str;echo "";echo "使用 trim: " . trim($str);?>以上代码的 HTML 输出如下(请查看源代码)&#xff1a;不使用 trim: Hello Worl…...

新疆seo/网站seo收费

在进行自然语言处理、文本分类聚类、推荐系统、舆情分析等研究在进行自然语言处理、文本分类聚类、推荐系统、舆情分析等研究在进行自然语言处理、文本分类聚类、推荐系统、舆情分析等研究在进行自然语言处理、文本分类聚类、推荐系统、舆情分析等研究在进行自然语言处理、文本…...

soho外贸网站建设/优化seo是什么意思

文章目录题目题目解析解题代码我的个人小站&#xff1a; acking-you.github.io题目 OJ平台 题目解析 实际上就是一个前缀和二分的处理&#xff0c;我一旦爆出前缀和二分&#xff0c;应该就都有思路了&#xff01; 解题代码 这里偷懒使用了STL&#xff0c;当然也可自己去写二…...