C++常见问题与思考

news2025/3/26 6:21:48

TLS(线程本地存储)原理

线程本地存储(Thread Local Storage,TLS)是一种机制,它允许每个线程拥有自己独立的变量实例,这些变量的生命周期与线程相同。也就是说,不同线程对同一个 TLS 变量的访问,实际上是在访问各自独立的副本,彼此之间互不干扰。

实现方式
  • 静态 TLS:在编译时就为每个线程分配 TLS 变量的存储空间。编译器会在可执行文件中预留相应的空间,当线程启动时,操作系统会为每个线程初始化这些 TLS 变量。在 C++ 中,可以使用 __declspec(thread)(Windows)或 __thread(GCC、Clang)关键字来声明静态 TLS 变量。例如:
// 使用 __thread 声明静态 TLS 变量
__thread int tls_variable = 0;
  • 动态 TLS:在运行时动态地为线程分配和管理 TLS 变量。操作系统提供了一系列的 API 来创建、访问和销毁动态 TLS 变量。在 C++ 中,可以使用 std::thread_local 关键字来声明动态 TLS 变量。例如:
// 使用 std::thread_local 声明动态 TLS 变量
thread_local int dynamic_tls_variable = 0;
工作原理
  • 数据结构:操作系统会为每个线程维护一个 TLS 数据结构,这个数据结构通常是一个数组或链表,用于存储该线程的所有 TLS 变量。
  • 索引机制:每个 TLS 变量都有一个唯一的索引,线程通过这个索引来访问自己的 TLS 变量。当线程访问一个 TLS 变量时,操作系统会根据线程 ID 和变量索引,从该线程的 TLS 数据结构中找到对应的变量副本。
  • 线程创建和销毁:当一个新线程创建时,操作系统会为该线程分配一个新的 TLS 数据结构,并将所有 TLS 变量初始化为默认值。当线程销毁时,操作系统会释放该线程的 TLS 数据结构。

如何实现一个无锁队列?

无锁队列是一种在多线程环境下不使用锁(如互斥锁)来实现线程安全的队列数据结构。无锁队列通常使用原子操作和内存屏障来保证多线程操作的正确性和一致性。下面将介绍如何使用 C++ 实现一个简单的无锁队列,这里采用单生产者单消费者(SPSC)的无锁队列作为示例。

实现思路

  • 使用原子操作来更新队列的头指针和尾指针,避免使用锁带来的性能开销。
  • 采用循环数组作为队列的底层存储结构。
  • 通过比较和交换(CAS)操作来确保在多线程环境下对头指针和尾指针的更新是原子的。

仿函数的优势

#include <iostream>
#include <vector>
#include <algorithm>

// 定义一个比较仿函数
class Greater {
public:
    bool operator()(int a, int b) const {
        return a > b;
    }
};

int main() {
    std::vector<int> numbers = {3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5};
    // 使用仿函数作为排序规则
    std::sort(numbers.begin(), numbers.end(), Greater());
    for (int num : numbers) {
        std::cout << num << " ";
    }
    std::cout << std::endl;
    return 0;
}
  • 可状态化:和普通函数不同,仿函数可以拥有自己的状态。也就是说,仿函数类可以有成员变量,这些成员变量能记录仿函数的状态。
  • 可作为模板参数:仿函数可以作为模板参数,在模板编程里能发挥很大作用。例如,std::sort函数就可以使用仿函数来定义排序规则。

野指针(Wild Pointer)

  • 定义:指向无效内存地址的指针,访问会导致未定义行为(崩溃、数据损坏)。
  • 常见场景
    • 未初始化的指针:未明确指向有效内存。
    • 指向已释放的内存(即悬垂指针)。
    • 指向超出作用域的局部变量

深浅拷贝

c++中引用有没有深浅拷贝的问题

  • 浅拷贝是指在拷贝对象时,仅复制对象的成员变量的值,而不复制成员变量所指向的资源。如果成员变量是指针、引用或其他对象的引用,那么浅拷贝后,源对象和目标对象的成员变量将指向相同的资源。
  • 深拷贝是指在拷贝对象时,不仅复制对象的成员变量的值,还会复制成员变量所指向的资源。深拷贝后,源对象和目标对象的成员变量将指向不同的资源,互不干扰。

string模拟实现拷贝构造和移动构造(手撕)

#include <iostream>
#include <cstring> // 用于std::strlen和std::strcpy

class MyString {
private:
    char* data; // 指向动态分配的字符数组

public:
    // 构造函数
    MyString(const char* str = "") {
        if (str) {
            data = new char[std::strlen(str) + 1]; // 分配内存,+1用于存储'\0'
            std::strcpy(data, str); // 复制字符串
        } else {
            data = new char[1];
            *data = '\0'; // 空字符串
        }
    }

    // 拷贝构造函数
    MyString(const MyString& other) {
        data = new char[std::strlen(other.data) + 1];
        std::strcpy(data, other.data);
        std::cout << "Copy constructor called" << std::endl;
    }

    // 移动构造函数
    MyString(MyString&& other) noexcept {
        data = other.data; // 直接接管other的资源
        other.data = nullptr; // 将other的指针置为空,避免析构时重复释放
        std::cout << "Move constructor called" << std::endl;
    }

    // 赋值运算符(拷贝赋值)
    MyString& operator=(const MyString& other) {
        if (this != &other) { // 防止自赋值
            delete[] data; // 释放当前对象的资源
            data = new char[std::strlen(other.data) + 1];
            std::strcpy(data, other.data);
        }
        return *this;
    }

    // 赋值运算符(移动赋值)
    MyString& operator=(MyString&& other) noexcept {
        if (this != &other) { // 防止自赋值
            delete[] data; // 释放当前对象的资源
            data = other.data; // 接管other的资源
            other.data = nullptr; // 将other的指针置为空
        }
        return *this;
    }

    // 析构函数
    ~MyString() {
        delete[] data; // 释放动态分配的内存
    }

    // 获取字符串内容
    const char* c_str() const {
        return data;
    }

    // 打印字符串内容
    void print() const {
        std::cout << data << std::endl;
    }
};

int main() {
    MyString str1("Hello, World!");
    MyString str2(str1); // 调用拷贝构造函数
    MyString str3(std::move(str1)); // 调用移动构造函数

    std::cout << "str1: ";
    str1.print();
    std::cout << "str2: ";
    str2.print();
    std::cout << "str3: ";
    str3.print();

    return 0;
}

内存泄露的问题、定位内存泄露的问题、处理内存泄露的问题

内存泄露的定义内存泄露(Memory Leak)是指程序在动态分配内存后,由于某种原因未能正确释放,导致这部分内存无法被重新使用。随着时间推移,程序占用的内存不断增加,最终可能导致系统内存耗尽,程序运行缓慢甚至崩溃。2\. 定位内存泄露问题定位内存泄露问题通常需要借助一些工具和方法,以下是一些常见的方法:(1)使用内存分析工具• Valgrind:一款开源的内存调试和性能分析工具,适用于Linux平台。它可以检测内存泄漏、越界访问、非法指针等问题。• 使用方法:在终端运行  valgrind ./your_program  ,它会生成详细的报告,指出内存泄露的位置。• AddressSanitizer:Google开源的内存错误检测工具,可以检测内存泄漏、缓冲区溢出等问题。• 使用方法:在编译时添加  -fsanitize=address  选项,运行程序时会自动检测内存问题。• LeakSanitizer:专门用于检测内存泄漏的工具。• mtrace:GNU Glibc自带的内存问题检测工具,通过记录  malloc  和  free  的调用来检测内存泄漏。• 使用方法:在代码中调用  mtrace()  和  muntrace()  ,并设置环境变量  MALLOC_TRACE  ,运行程序后会生成日志文件,通过分析日志可以定位内存泄漏问题。(2)代码审查定期审查代码,查找未释放的内存分配。重点关注以下几点:• 确保每个  malloc  、  calloc  、  realloc  等动态分配内存的函数都有对应的  free  调用。• 检查指针重新赋值、错误的内存释放以及返回值的不正确处理等情况。(3)日志和调试在程序中添加日志记录内存分配和释放的操作。通过分析日志,可以确定哪些内存分配没有被释放。此外,使用调试器(如GDB)也可以追踪内存泄漏。(4)自定义内存分配函数创建自定义的内存分配和释放函数,记录每次分配和释放的内存信息。通过这种方式可以更直观地检测内存泄漏。3\. 处理内存泄露问题一旦发现内存泄露问题,需要采取以下措施进行处理:(1)手动释放内存在程序中进行内存分配时,确保及时释放不再需要的内存。如果忘记释放内存,就会导致内存泄漏。(2)使用智能指针在C++中,使用智能指针(如  std::unique_ptr  、  std::shared_ptr  )可以自动管理内存,避免手动释放内存的繁琐操作,从而减少内存泄漏的风险。(3)修复代码中的错误根据内存分析工具的报告或日志信息,修复代码中的错误。例如:• 确保在指针重新赋值前释放原有内存。• 修复错误的内存释放逻辑。• 正确处理函数返回值,避免内存泄漏。(4)定期进行垃圾回收对于一些支持垃圾回收的语言(如Java、Python),可以定期进行垃圾回收,以释放不再使用的内存。4\. 预防内存泄露预防内存泄露比修复内存泄露更为重要,以下是一些预防内存泄露的方法:• 明确内存所有权:每次分配内存时,明确哪个部分负责释放该内存。• 使用RAII(资源获取即初始化):在C++中,通过RAII机制确保资源在对象生命周期结束时自动释放。• 避免使用裸指针:尽量使用智能指针或容器来管理动态内存。• 编写单元测试:通过单元测试检查内存分配和释放的正确性。

迭代器失效

序列式容器(如vectordeque

插入元素导致迭代器失效
  • vector:当向vector中插入元素时,如果当前容量不足,vector会重新分配一块更大的内存,并将原有元素复制到新内存中,然后释放旧内存。这会导致所有指向原vector的迭代器、指针和引用都失效。
#include <iostream>
#include <vector>

int main() {
    std::vector<int> vec = {1, 2, 3};
    auto it = vec.begin();
    vec.insert(vec.begin(), 0); // 插入元素,可能导致迭代器失效
    // *it = 10; // 错误,此时迭代器it可能已失效
    return 0;
}
  • deque:在deque的中间插入元素会使所有迭代器、指针和引用失效;在deque的两端插入元素,只有指向插入点的迭代器会失效。

 std::deque  内部实现是一个块序列,每个块存储固定数量的元素。当删除中间元素时,为了保持块的连续性和完整性,可能会导致以下操作:

  • 元素移动:删除中间元素后,后面的元素需要向前移动以填补空缺。
  • 块调整:可能需要重新分配块,或者调整块的边界。

最终导致迭代器失效:由于元素的物理位置发生了变化,所有迭代器的指向都会变得不确定。

删除元素导致迭代器失效
  • vector:删除vector中的元素时,被删除元素之后的所有迭代器、指针和引用都会失效。
#include <iostream>
#include <vector>

int main() {
    std::vector<int> vec = {1, 2, 3};
    auto it = vec.begin() + 1;
    vec.erase(vec.begin()); // 删除元素,后续迭代器失效
    // *it = 10; // 错误,此时迭代器it已失效
    return 0;
}
  • deque:删除deque中的元素时,除了被删除元素的迭代器失效外,若删除的不是两端元素,所有迭代器、指针和引用都会失效。

关联式容器(如setmap

插入元素导致迭代器失效

对于setmap等关联式容器,插入元素不会使任何迭代器、指针和引用失效。因为关联式容器使用红黑树等数据结构实现,插入操作只是在树中添加新节点,不会影响原有节点的位置。

#include <iostream>
#include <set>

int main() {
    std::set<int> mySet = {1, 2, 3};
    auto it = mySet.begin();
    mySet.insert(4); // 插入元素,迭代器不会失效
    std::cout << *it << std::endl; // 可以正常使用迭代器
    return 0;
}
删除元素导致迭代器失效

删除关联式容器中的元素时,被删除元素的迭代器会失效,但其他迭代器不受影响。

#include <iostream>
#include <set>

int main() {
    std::set<int> mySet = {1, 2, 3};
    auto it = mySet.begin();
    auto nextIt = std::next(it);
    mySet.erase(it); // 删除元素,当前迭代器失效
    // *it = 10; // 错误,此时迭代器it已失效
    std::cout << *nextIt << std::endl; // 可以正常使用其他迭代器
    return 0;
}

解决迭代器失效问题的方法

  • 重新获取迭代器:在进行插入或删除操作后,重新获取迭代器,确保其指向有效的元素。
  • 使用返回值更新迭代器:一些容器的插入和删除操作会返回有效的迭代器,可以使用这些返回值更新迭代器。

const的使用

  • 1\. 声明常量变量  const  可以用来声明常量变量,确保其值在初始化后不能被修改。cppconst int MAX_SIZE = 100; // MAX_SIZE是一个常量,不能被修改
  • 2\. 常量成员函数在类中,  const  可以修饰成员函数,表示该成员函数不会修改对象的任何成员变量。这对于保证对象的不可变性非常有用。
  • 3\. 常量对象可以使用  const  修饰整个对象,表示该对象的所有成员变量都不能被修改。对于常量对象,只能调用其常量成员函数。
  • 4\. 常量引用  const  可以用于声明引用,表示引用所指向的对象不能被修改。常量引用常用于函数参数,以避免不必要的拷贝。
  • 5\. 常量指针和指针常量• 常量指针:指针所指向的内容不能被修改。
  • 常量指针常量:指针本身和指针所指向的内容都不能被修改。cppconst int* const ptr = &value; // 
  • 6\. 常量表达式C++11引入了  constexpr  ,用于声明编译时常量。  constexpr  比  const  更严格,它要求表达式在编译时必须能够求值。cppconstexpr int MAX_SIZE = 100; // 编译时常量
  • 7\. 常量成员变量类中的成员变量可以被声明为  const  ,表示该成员变量在对象初始化后不能被修改。常量成员变量必须在构造函数的初始化列表中初始化。
  • 8\. 常量与模板  const  可以用于模板参数,表示模板参数是一个常量。
  • 9\. 常量与函数返回值函数可以返回  const  类型的值,但通常不推荐,因为返回  const  值会限制函数的使用。
  • 10\. 常量与类型别名

dynamic_cast

功能

dynamic_cast 主要用于在继承体系中进行安全的向下转型(从基类指针或引用转换为派生类指针或引用),并且会在运行时检查转型的有效性。如果转型失败,对于指针类型会返回 nullptr,对于引用类型会抛出 std::bad_cast 异常。

使用场景

常用于多态环境下,当你持有一个基类指针或引用,但需要访问派生类特有的成员时,可以使用 dynamic_cast 进行安全的类型转换。

示例代码
#include <iostream>

class Base {
public:
    virtual void print() { std::cout << "Base" << std::endl; }
    virtual ~Base() {}
};

class Derived : public Base {
public:
    void print() override { std::cout << "Derived" << std::endl; }
    void derivedFunction() { std::cout << "Derived function" << std::endl; }
};

int main() {
    Base* basePtr = new Derived();
    Derived* derivedPtr = dynamic_cast<Derived*>(basePtr);
    if (derivedPtr) {
        derivedPtr->derivedFunction();
    }
    delete basePtr;
    return 0;
}
注意事项
  • dynamic_cast 只能用于含有虚函数的类层次结构,因为它依赖于虚函数表来进行运行时类型检查。
  • 运行时类型检查会带来一定的性能开销。

static_cast

功能

static_cast 是一种编译时的类型转换,它可以用于各种基本类型之间的转换,以及在继承体系中进行向上转型(从派生类指针或引用转换为基类指针或引用)和向下转型(但不进行运行时检查)。

使用场景
  • 基本类型的转换,如 int 转 double
  • 继承体系中的向上转型,这是安全的,因为派生类对象包含基类对象的所有成员。
  • 显式调用类的转换构造函数或转换运算符。
示例代码
#include <iostream>

class Base {};
class Derived : public Base {};

int main() {
    int num = 10;
    double d = static_cast<double>(num);

    Derived derived;
    Base* basePtr = static_cast<Base*>(&derived); // 向上转型

    return 0;
}
注意事项
  • static_cast 不进行运行时类型检查,因此向下转型时如果类型不匹配,可能会导致未定义行为。

const_cast

功能

const_cast 主要用于去除或添加 const 或 volatile 修饰符。它只能用于改变对象的常量性或易变性,不能改变对象的类型。

使用场景

当你需要在某些情况下修改一个原本被声明为 const 的对象时,可以使用 const_cast 去除 const 修饰符,但要确保这种修改是安全的。

示例代码
#include <iostream>

void printNonConst(int& num) {
    std::cout << num << std::endl;
}

int main() {
    const int num = 10;
    int& nonConstNum = const_cast<int&>(num);
    // nonConstNum = 20; // 不建议修改,可能导致未定义行为
    printNonConst(nonConstNum);
    return 0;
}
注意事项
  • 去除 const 修饰符后修改原本为 const 的对象可能会导致未定义行为,应谨慎使用。

reinterpret_cast

功能

reinterpret_cast 是一种最危险的类型转换,它可以将任意指针类型转换为其他指针类型,甚至可以将指针转换为整数类型或反之。它不进行任何类型检查,只是简单地重新解释二进制位。

使用场景
  • 底层编程,如在某些系统编程中需要将指针转换为整数进行地址计算。
  • 处理一些特殊的硬件相关操作。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2321790.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

从零开始:使用Luatools工具高效烧录Air780EPM核心板项目的完整指南

本文将深入讲解如何使用Luatools工具烧录一个具体的项目到Air780EPM开发板中。如何使用官方推荐的Luatools工具&#xff08;一款跨平台、命令行驱动的烧录利器&#xff09;&#xff0c;通过“环境配置→硬件连接→参数设置→一键烧录”四大步骤&#xff0c;帮助用户实现Air780E…

一套云HIS系统源码,系统融合HIS与EMR,基于云端部署,采用B/S架构与SaaS模式

云HIS系统完全基于云端部署&#xff0c;采用B/S架构&#xff0c;并通过软件即服务&#xff08;SaaS&#xff09;的形式面向二级及以下医院可快速交付、便捷运维、云化的医院核心业务平台产品。融合医院HIS和EMR两大主营系统&#xff0c;构建涵盖患者、费用、医嘱、电子病历等核…

C++数据结构(搜索二叉树)

1.二叉树搜索的概念 二叉搜索数也成为二叉排序树&#xff0c;它或者是一颗空树&#xff0c;或者是满足以下性质的树&#xff1a; 1.若他的左子树不为空&#xff0c;则左子树上的所有节点的值都小于等于根节点的值。 2.若他的右子树不为空&#xff0c;则右子树上的所有节点的值…

OpenCV图像拼接(6)图像拼接模块的用于创建权重图函数createWeightMap()

操作系统&#xff1a;ubuntu22.04 OpenCV版本&#xff1a;OpenCV4.9 IDE:Visual Studio Code 编程语言&#xff1a;C11 算法描述 cv::detail::createWeightMap 是 OpenCV 库中用于图像拼接模块的一个函数&#xff0c;主要用于创建权重图。这个权重图在图像拼接过程中扮演着重…

炫酷的HTML5粒子动画特效实现详解

炫酷的HTML5粒子动画特效实现详解 这里写目录标题 炫酷的HTML5粒子动画特效实现详解项目介绍技术栈项目架构1. HTML结构2. 样式设计 核心实现1. 粒子类设计2. 动画效果实现星空效果烟花效果雨滴效果 3. 鼠标交互 性能优化效果展示总结 项目介绍 本文将详细介绍如何使用HTML5 C…

YoloV8训练和平精英人物检测模型

概述 和平精英人物检测&#xff0c;可以识别游戏中所有人物角色&#xff0c;并通过绘制框将人物选中&#xff0c;训练的模型仅仅具有识别功能&#xff0c;可以识别游戏中的视频、图片等文件&#xff0c;搭配Autox.js可以推理&#xff0c;实现实时绘制&#xff0c;但是对手机性…

BC93 公务员面试

&#x1f680;个人主页&#xff1a;BabyZZの秘密日记 &#x1f4d6;收入专栏&#xff1a;C语言练习题分享 &#x1f30d;文章目入 #include <stdio.h> int main() {int score 0, max 0, min 100, sum 0, count 0; while (scanf("%d", &score) ! EOF){…

3.0 Disruptor的使用介绍(一)

Disruptor: 其官网定义为&#xff1a;“A High Performance Inter-Thread Messaging Library”&#xff0c;即&#xff1a;线程间的高性能消息框架&#xff0c;与Labview的生产者、消费者模型很相似。 其组成部分比较多&#xff0c;先介绍几个常用的概念&#xff1a; …

[深度学习]图像分类项目-食物分类

图像分类项目-食物分类(监督学习和半监督学习) 文章目录 图像分类项目-食物分类(监督学习和半监督学习)项目介绍数据处理设定随机种子读取文件内容图像增广定义Dataset类 模型定义迁移学习 定义超参Adam和AdamW 训练过程半监督学习定义Dataset类模型定义定义超参训练过程 项目介…

java8循环解压zip文件---实现Excel文件数据追加

java8循环追加Excel数据 实际遇到问题&#xff1a;定期获取zip文件&#xff0c;zip文件内有几个固定模板的Excel文件&#xff0c;有的Excel文件可能还包含多个sheet。 有段时间一次性获取到好几个zip包&#xff0c;需要将这些包都解压&#xff0c;并且按照不同的文件名、sheet进…

基于SpringBoot的电影售票系统

作者&#xff1a;计算机学姐 开发技术&#xff1a;SpringBoot、SSM、Vue、MySQL、JSP、ElementUI、Python、小程序等&#xff0c;“文末源码”。 专栏推荐&#xff1a;前后端分离项目源码、SpringBoot项目源码、Vue项目源码、SSM项目源码、微信小程序源码 精品专栏&#xff1a;…

SQL Server 2022 安装问题

一、安装与配置问题 1. SQL Server 2022 安装失败怎么办&#xff1f; 常见原因&#xff1a; 硬件或操作系统不满足最低要求&#xff08;如内存、磁盘空间不足&#xff09;。未关闭防火墙或杀毒软件。之前版本的 SQL Server 残留文件未清理。 解决方案&#xff1a; 确保硬件配…

MySQL 8.0.41安装教程(附安装包)mysql8.0.41图文详细安装教程

文章目录 前言一、MySQL 8.0.41下载安装包二、MySQL 8.0.41安装教程1.启动安装程序2.选择安装模式3.选定安装组件4.确认安装设置5.执行安装操作6.安装进行中7.设置数据库密码8.继续点击下一步9.执行配置操作10.完成配置11. 再次点击下一步12.结束安装向导 三、MySQL 8.0.41配置…

深入解析 C++20 中的 std::bind_front:高效函数绑定与参数前置

文章目录 1. 什么是 std::bind_front&#xff1f;2. 使用 std::bind_front2.1 基本用法2.2 绑定多个参数 3. 优势与特点3.1 简化代码3.2 支持可调用对象3.3 支持完美转发 4. 实际应用场景4.1 事件处理4.2 算法通用化4.3 成员函数调用 5. 总结 在现代 C 编程中&#xff0c;函数绑…

python裁剪nc文件数据

问题描述&#xff1a; 若干个nc文件储存全球的1850-2014年月尺度的mrro数据(或其他数据)&#xff0c;从1850-1到2014-12一共1980个月&#xff0c;要提取出最后35年1980.1~2014.12年也就是420个月的数据。 代码实现 def aaa(input_file,output_file,bianliang,start_index,en…

CSS网格布局Grid

目录 一、Grid 网格布局 1.Grid 布局基础 2.网格容器属性 3.网格项目属性 4.高级功能 5.典型应用场景 6.最佳实践 二、Flex和Grid对比 示例&#xff1a; 一、Grid 网格布局 CSS Grid 是一种强大的二维布局系统&#xff0c;能够以行和列的方式精确控制网页布局。它比传…

医院挂号预约小程序|基于微信小程序的医院挂号预约系统设计与实现(源码+数据库+文档)

医院挂号预约小程序 目录 基于微信小程序的医院挂号预约系统设计与实现 一、前言 二、系统功能设计 三、系统实现 1、小程序用户端 2、系统服务端 &#xff08;1&#xff09; 用户管理 &#xff08;2&#xff09;医院管理 &#xff08;3&#xff09;医生管理 &#xf…

蓝桥杯第十届 特别的数

题目描述 小明对数位中含有 2、0、1、9 的数字很感兴趣&#xff08;不包括前导 0&#xff09;&#xff0c;在 1 到 40 中这样的数包括 1、2、9、10 至 32、39 和 40&#xff0c;共 28 个&#xff0c;他们的和是 574。 请问&#xff0c;在 1 到 n 中&#xff0c;所有这样的数的…

Qt开发:QInputDialog的使用

文章目录 一、QInputDialog的介绍二、 QInputDialog的基本用法三、使用 QInputDialog的实例四、QInputDialog的信号与槽 一、QInputDialog的介绍 QInputDialog 是 Qt 提供的一个对话框类&#xff0c;用于获取用户输入的文本、整数或浮点数。它提供了简单易用的静态方法和可定制…