佛山市外贸网站建设公司做网站一共需要多少钱

张小明 2025/12/28 19:27:27
佛山市外贸网站建设公司,做网站一共需要多少钱,一个网站多少钱?,阿里巴巴做网站需要多少钱执行方式#xff1a; 程序执行#xff1a; 示例显示了程序的执行命令#xff1a;$ ./a.out。这里使用的是 Linux 风格的命令行执行#xff0c;其中没有指定输出文件名#xff0c;因此程序默认的输出文件名为 a.out。这是 Unix 和类 Unix 系统中默认的可执行文件名称。 …执行方式程序执行示例显示了程序的执行命令$ ./a.out。这里使用的是 Linux 风格的命令行执行其中没有指定输出文件名因此程序默认的输出文件名为a.out。这是 Unix 和类 Unix 系统中默认的可执行文件名称。样式与约定头文件stringstring代表一个 C 头文件其功能是处理与字符串相关的操作。C 标准库提供了std::string类型该类型用于表示和处理字符串。C 属性标记[[xyz]][[xyz]]是 C 中的一种属性attribute语法。C 属性用于向编译器提供附加信息或者指示编译器做特定的优化或验证。例如[[nodiscard]]属性可以告诉编译器忽略返回值可能被丢弃的警告。xyz是属性的名字在 C 中可以是预定义的属性如nodiscard或者是用户自定义的属性。总结代码中提到的./a.out是在类 Unix 系统中执行可执行文件的常见命令。string头文件提供了std::string类使得程序能够轻松操作字符串。[[xyz]]是一种 C 属性的语法它允许在代码中添加编译器指令影响程序的编译行为或其他特性。涉及 C 中的Compressed Pair技术具体是关于如何通过std::unique_ptr和fclose函数来优化内存使用。以下是详细的理解代码解析autofstd::unique_ptrFILE,decltype(fclose){fopen(SomeFile.txt,r),fclose};std::unique_ptrFILE, decltype(fclose)这里使用了 C 的std::unique_ptr它是一种智能指针主要用于管理动态分配的内存资源确保资源在不再需要时自动释放。FILE是 C 标准库中的一个类型用于表示文件流。这里表示std::unique_ptr管理一个文件指针由fopen返回的指针。第二个模板参数是decltype(fclose)表示std::unique_ptr将使用fclose作为自定义删除器。当unique_ptr被销毁时它会调用fclose来关闭文件。fopen(SomeFile.txt, r)fopen函数用于打开文件r表示以只读模式打开名为SomeFile.txt的文件。fclosefclose是fclose函数的地址用作自定义删除器。这意味着当std::unique_ptr销毁时它将调用fclose来关闭文件。断言static_assert(sizeof(f)(2*sizeof(void*)));static_assertstatic_assert用于在编译时检查条件是否成立。如果条件不成立编译器会抛出错误。这是一种静态断言检查某些条件是否在编译时满足。sizeof(f)sizeof(f)计算的是变量f的内存大小。2 * sizeof(void*)sizeof(void*)是指指针的大小通常为 4 或 8 字节取决于系统架构。由于std::unique_ptr内部通常存储两个指针一个是对象的指针即文件指针FILE*另一个是自定义删除器的指针即fclose的指针。因此sizeof(f)应该等于两个指针的大小即2 * sizeof(void*)。解释Compressed Pair这段代码中的std::unique_ptrFILE, decltype(fclose)利用了 C 的优化技巧——压缩对Compressed Pair。压缩对是一种技术旨在将两个指针压缩成一个对象的两个成员通常是通过内存对齐和合理布局来实现的。在这种情况下f由两个指针组成一个指向文件的指针另一个指向文件关闭函数的指针。通过这种方式内存占用被压缩成两个指针大小通常是两个void*的大小从而节省了内存空间。通过使用std::unique_ptr和fclose作为自定义删除器程序员无需手动管理文件的关闭避免了内存泄漏或文件未关闭的风险。总结这段代码展示了如何利用std::unique_ptr和Compressed Pair技术来高效地管理资源确保内存和文件管理的高效性。static_assert断言用于确保f的内存大小等于两个指针的大小验证压缩对的效果。空基类优化Empty Base Optimization, EBO技术下面是详细的解释代码解析1.Base 类classBase{public:voidFun(){puts(HelloEBO!);}};Base类有一个公有成员函数Fun()该函数使用puts输出 “HelloEBO!” 字符串。这个类没有数据成员因此它是一个空类只有成员函数。2.Derived 类classDerived:publicBase{int32_tmData{};public:};Derived类是从Base类派生出来的并且增加了一个名为mData的int32_t类型的成员变量默认初始化为 0。Derived类中没有成员函数仅包含从Base类继承的Fun()成员函数。3.Use 函数voidUse(){Derived d{};static_assert(sizeof(d)sizeof(int32_t));// 编译时断言d.Fun();// 调用 Fun()}Use函数中创建了一个Derived类型的对象d并且使用static_assert检查d的大小是否等于int32_t的大小。static_assert是编译时断言只有在编译时条件为真时才会通过。如果条件不成立编译会报错。sizeof(d)计算的是d对象的内存占用大小。由于Derived类除了mData之外没有其他成员变量而Base类由于空基类优化EBO的原因不会占用额外空间所以d的大小仅为mData的大小也就是sizeof(int32_t)。最后调用d.Fun()打印字符串 “HelloEBO!”。空基类优化EBOEBOEmpty Base Optimization是一种优化技术主要是为了避免空基类在派生类中占用额外的内存空间。在 C 中如果一个类没有成员变量即空类它仍然需要一些空间来保持其类的身份如虚函数表指针等这通常会导致不必要的内存开销。但是在某些情况下编译器会通过空基类优化EBO来避免这种开销。当一个类是空基类时编译器可以通过将其嵌入到派生类中并不占用额外的内存从而避免空基类的内存浪费。解释为什么static_assert(sizeof(d) sizeof(int32_t))能通过由于Base类没有成员变量仅有一个成员函数编译器会优化它为一个 “空” 类即不占用任何内存或非常少的内存。Derived类包含一个int32_t类型的成员变量mData因此sizeof(Derived)应该是sizeof(int32_t)。由于没有虚函数或其他额外的成员Derived类的大小正好是int32_t的大小符合static_assert的断言条件。空基类优化的关键在没有 EBO 的情况下Derived类的大小通常会大于单一成员变量mData的大小因为即使是空的基类也会占用一定的内存空间。但是通过空基类优化空基类Base的内存开销被消除了使得Derived类的大小仅由其数据成员mData决定。总结这段代码演示了空基类优化EBO技术的使用。在派生类Derived中尽管继承了一个空的基类Base但由于空基类优化Base并没有占用额外的内存空间最终Derived类的大小等于int32_t类型的大小即sizeof(int32_t)。通过static_assert可以验证这种优化效果确保没有额外的内存浪费。如果你有任何问题或想进一步探讨这个话题随时告诉我这段代码定义了一个default_delete模板结构体下面是详细的解析代码分析1.模板结构体default_deletetemplateclassTstructdefault_delete{default_delete()default;// 默认构造函数这是一个模板结构体接收一个类型参数T并定义了一个默认构造函数default_delete()该构造函数使用默认行为即不进行额外的操作。2.operator()操作符constexprvoidoperator()(T*ptr)constnoexcept{static_assert(sizeof(T)0,cant delete an incomplete type);deleteptr;}operator()是重载的函数调用操作符允许default_delete作为一个可调用对象来使用。该操作符接受一个T*类型的指针ptr表示要删除的对象。constexpr表示该函数是一个编译时常量函数它可以在常量表达式中使用例如数组大小计算等。noexcept表示该函数不会抛出任何异常。在 C 中noexcept可以帮助编译器进行优化并告知调用者该函数不会抛出异常从而提高程序的安全性。static_assert(sizeof(T) 0, cant delete an incomplete type);这是一个静态断言用于确保类型T不是不完整类型incomplete type。不完整类型是指那些没有完全定义的类型比如前向声明的类类型。sizeof(T)获取类型T的大小若类型不完整sizeof(T)将无法计算出有效大小因此会触发编译错误断言失败。delete ptr;调用delete运算符来释放ptr指向的内存空间。delete运算符用于销毁通过new运算符分配的内存确保内存得到正确释放。代码总结这个default_delete结构体是一个自定义的删除器deleter用于配合智能指针如std::unique_ptr自动释放内存。其功能与标准库中的std::default_delete类似以下是代码的关键点默认构造函数构造函数是默认的不做任何操作。operator()操作符允许default_delete对象像函数一样调用用于删除指针指向的内存。静态断言静态断言检查类型T是否是完整类型即已完全定义避免删除不完整类型的对象。删除内存使用delete运算符释放动态分配的内存。应用场景这个default_delete结构体通常用在智能指针如std::unique_ptr中作为自定义删除器的一部分。智能指针会在其生命周期结束时自动调用删除器来释放资源而default_delete作为删除器可以确保删除动态分配的内存。通过使用static_assert确保只有完整类型的对象可以被删除避免潜在的错误。补充说明为什么需要static_assert(sizeof(T) 0)在 C 中如果类型T是不完整类型编译器无法知道它的大小这可能会导致错误的内存释放。通过static_assert我们确保只有已完整定义的类型才能通过此删除器进行删除。例如如果T是一个前向声明的类类型class A;编译器无法知道A类的完整定义此时尝试使用delete删除A类型的指针会导致错误。delete运算符的使用delete运算符只能用于通过new或new[]分配的内存。如果ptr不是通过new分配的内存调用delete会导致未定义的行为。结论default_delete结构体是一个简单但非常重要的功能它确保了内存的安全删除避免了不完整类型的问题并且与现代 C 中的智能指针配合使用时能够有效管理内存的生命周期。如果你有进一步的问题或需要更详细的代码解析随时告诉我以下是你提供的unique_ptr类的完整实现templateclassT,classDeldefault_deleteTclassunique_ptr{// CompressedPair 用于存储删除器和原始指针CompressedPairDel,T*mPair;// Apublic:// 构造函数接收一个指向 T 类型对象的指针并将其存储在 mPair 中unique_ptr(T*ptr):mPair{ptr}{}// B// 构造函数接收一个指向 T 类型对象的指针和一个自定义的删除器 deleterunique_ptr(T*ptr,Del deleter):mPair{deleter,ptr}{}// C// 拷贝构造函数被删除禁止拷贝unique_ptr(constunique_ptr)delete;// 拷贝赋值运算符被删除禁止拷贝赋值unique_ptroperator(constunique_ptr)delete;// 移动构造函数接受一个右值引用将资源从 src 移动到当前对象unique_ptr(unique_ptrsrc):mPair{std::exchange(src.mPair.second,nullptr)}{}// 移动赋值运算符将 src 的资源移动到当前对象unique_ptroperator(unique_ptrsrc){// 交换当前对象和 src 对象的指针和删除器mPair.secondstd::exchange(src.mPair.second,mPair.second);mPair.firststd::exchange(src.mPair.first,mPair.first);return*this;}// 析构函数如果 mPair.second (指针) 非空则使用 mPair.first (删除器) 来释放资源~unique_ptr(){if(mPair.second){mPair.first(mPair.second);// 使用删除器释放资源}}// 解引用运算符返回 mPair.second (原始指针)T*operator-(){returnmPair.second;}};详细注释类模板声明templateclassT,classDeldefault_deleteTclassunique_ptr{T是智能指针管理的对象类型。Del是删除器类型默认为default_deleteT它会调用delete操作符释放T类型的资源。如果用户提供了删除器Del会被替换成自定义的删除器。CompressedPairDel, T* mPair;CompressedPair是一个压缩对数据结构用于存储两个成员删除器 (Del) 和原始指针 (T*)。mPair.first存储删除器mPair.second存储指向对象的指针。这样存储可以优化内存布局避免额外的内存开销。构造函数unique_ptr(T*ptr):mPair{ptr}{}unique_ptr(T*ptr,Del deleter):mPair{deleter,ptr}{}第一个构造函数接受一个指向T类型对象的指针将其存储在mPair.second中。第二个构造函数允许用户提供一个自定义的删除器deleter并将其与ptr一起存储在mPair中。拷贝构造函数与拷贝赋值运算符被删除unique_ptr(constunique_ptr)delete;unique_ptroperator(constunique_ptr)delete;禁止unique_ptr的拷贝构造和拷贝赋值操作。这是为了确保智能指针管理的资源只有一个所有者避免资源的重复释放。移动构造函数unique_ptr(unique_ptrsrc):mPair{std::exchange(src.mPair.second,nullptr)}{}移动构造函数将源对象src的资源指针和删除器移动到当前对象。使用std::exchange来交换src.mPair.second指针与nullptr以确保源对象不再拥有资源。移动赋值运算符unique_ptroperator(unique_ptrsrc){mPair.secondstd::exchange(src.mPair.second,mPair.second);mPair.firststd::exchange(src.mPair.first,mPair.first);return*this;}移动赋值运算符会交换当前对象与源对象src的资源。交换指针和删除器的内容后源对象的指针和删除器会被重置为默认值。析构函数~unique_ptr(){if(mPair.second){mPair.first(mPair.second);// 使用删除器释放资源}}析构函数会在unique_ptr被销毁时调用。如果mPair.second存储的指针非空则调用删除器释放资源。解引用运算符T*operator-(){returnmPair.second;}解引用运算符重载使得可以通过unique_ptr访问所管理对象的成员。返回原始指针mPair.second从而可以像操作普通指针一样访问对象的成员。总结unique_ptr是一个智能指针类通过压缩对 (CompressedPair) 来高效存储删除器和原始指针避免额外的内存开销。它的设计遵循唯一所有权的理念不允许拷贝只支持移动语义确保资源的唯一拥有者。析构时自动释放资源避免了手动调用delete可能带来的错误。通过重载解引用运算符 (operator-)可以像访问原始指针一样使用unique_ptr。这种智能指针设计可以有效地管理动态分配的资源确保资源管理的安全性和简洁性。代码总结unique_ptr是一个智能指针类它通过内部存储的原始指针和删除器确保资源的唯一所有权和自动释放。其核心设计理念是不可拷贝性和可移动性即同一个资源只能被一个unique_ptr拥有。当unique_ptr被销毁时它会使用其删除器来释放资源这通常是delete运算符除非提供了自定义的删除器。CompressedPair用于节省内存它将删除器和指针紧密组合减少了内存开销。支持移动语义但不支持拷贝语义以确保资源管理的唯一性。相关功能和应用删除器通过default_delete或自定义删除器unique_ptr可以灵活地管理资源适应不同的资源释放方式例如释放数组或通过自定义函数释放资源。内存管理通过unique_ptr自动管理资源避免了手动调用delete可能带来的错误。operator-允许通过unique_ptr像原始指针一样访问对象的成员简化了代码。下面是你提供的CompressedPair结构体代码带有详细的注释templatetypenameT,typenameUstructCompressedPair{// 使用 [[no_unique_address]] 属性来告知编译器T 和 U 的地址可以合并优化内存布局[[no_unique_address]]T first;[[no_unique_address]]U second;// 构造函数接受一个 U 类型的参数初始化 secondCompressedPair(U s):second{s}{}// 构造函数接受一个 T 类型的参数和一个 U 类型的参数分别初始化 first 和 secondCompressedPair(T f,U s):first{f},second{s}{}};详细注释CompressedPair结构体该结构体是一个包含两个成员的简单数据结构通常用于将两个类型的值存储在一起。它是通过模板实现的允许存储任何类型的两个值。[[no_unique_address]]属性[[no_unique_address]]是 C20 引入的一个属性用来告知编译器可以优化两个成员的内存布局合并它们的地址。在没有这个属性时如果T和U分别有不同的大小和对齐要求编译器通常会为它们分配不同的内存空间。通过使用[[no_unique_address]]属性编译器可以根据需要将T和U的内存布局进行压缩优化减少内存浪费。构造函数第一个构造函数CompressedPair(U s)只接受一个类型为U的参数并初始化second成员。第二个构造函数CompressedPair(T f, U s)同时接受T类型和U类型的参数并分别初始化first和second成员。说明CompressedPair是一个非常简单的结构体可以用于存储两个不同类型的数据。通过使用[[no_unique_address]]属性它对内存布局进行了优化减少了内存空间的浪费。这种结构体可以广泛应用于存储任意类型的组合通常用于实现某些容器或者智能指针等数据结构例如前面的unique_ptr设计中使用了CompressedPair来存储指针和删除器。// 定义一个模板类型别名 unique_ptr_deleter// 它接收两个模板参数T 表示智能指针管理的对象类型DeleteFn 是自定义的删除函数。templatetypenameT,autoDeleteFnusingunique_ptr_deleterstd::unique_ptrT,decltype([](T*obj){DeleteFn(obj);});// 使用一个 lambda 表达式包装删除函数 DeleteFn// 创建一个 unique_ptr_deleter 类型的对象 f// 该对象管理一个 FILE* 类型的资源// 使用 fclose 作为删除器来关闭文件。autofunique_ptr_deleterFILE,fclose{fopen(SomeFile.txt,r)};// 静态断言确保 f 的大小等于指针大小通常是 void* 的大小// 这说明 unique_ptr 只存储一个原始指针删除器不会增加额外的内存开销。static_assert(sizeof(f)sizeof(void*));这段代码定义了一个模板类型别名unique_ptr_deleter用于创建一个带自定义删除函数的std::unique_ptr。模板类型别名templatetypenameT,autoDeleteFnusingunique_ptr_deleterstd::unique_ptrT,decltype([](T*obj){DeleteFn(obj);});这是一个模板类型别名它的作用是为std::unique_ptr提供一个自定义删除器deleter。这个删除器是由模板参数DeleteFn和一个 lambda 表达式构成。T是std::unique_ptr管理的对象的类型。DeleteFn是删除操作的函数类型为auto可以是任意类型的删除器函数。该删除器必须接受一个T*类型的指针并执行删除操作。由于std::unique_ptr的第二个模板参数是删除器类型因此使用decltype来推导 lambda 的类型。f的初始化autofunique_ptr_deleterFILE,fclose{fopen(SomeFile.txt,r)};这里使用unique_ptr_deleter来创建一个std::unique_ptr它管理一个FILE*类型的资源并且使用fclose作为自定义删除器。fopen(SomeFile.txt, r)打开文件并返回FILE*然后传递给unique_ptr_deleter它会在unique_ptr被销毁时自动调用fclose来关闭文件。static_assertstatic_assert(sizeof(f)sizeof(void*));这行代码验证了f的大小是否等于void*的大小。因为std::unique_ptr是一个轻量级的智能指针它通常只存储一个原始指针并且自定义删除器通常不会增加指针的大小。解释这段代码的关键点在于通过unique_ptr_deleter定义了一个智能指针类型它允许开发者为std::unique_ptr提供一个自定义的删除器函数。通常std::unique_ptr使用delete或delete[]作为默认删除器但此处使用了自定义的删除函数fclose来关闭文件。通过这种方式std::unique_ptr能够在资源生命周期结束时自动执行适当的清理工作。#includememorytemplatetypenameT,autoDeleteFnusingunique_ptr_deleterstd::unique_ptrT,decltype([](T*obj)static{DeleteFn(obj);});//c23intmain(){autofunique_ptr_deleterFILE,fclose{fopen(SomeFile.txt,r)};static_assert(sizeof(f)sizeof(void*));}https://godbolt.org/z/WGPv39xxs代码结构分析structstring{size_t mSize{};// 字符串的当前长度size_t mCapacity{};// 字符串的容量包括实际存储字符的大小和可能的额外空间char*mData{};// 指向字符串数据的指针如果字符串超过 SSO 的大小就指向堆分配的内存charmSSOBuffer[16]{};// 小字符串缓冲区SSO用于存储小于或等于 16 字符的字符串boolmIsSSO{true};// 标志表示当前字符串是否使用 SSO};static_assert(sizeof(string)48);各成员变量的解释mSize:表示字符串的当前大小即存储的字符数量不包括终止符。mCapacity:表示字符串的容量通常容量会比大小大一些以避免频繁的内存重新分配。如果字符串过长mData会指向堆内存。mData:这是一个指针当字符串的大小超过 SSO 能提供的空间时mData会指向堆上的内存存储实际的字符串内容。mSSOBuffer:这是一个数组大小为 16 字节用于存储短字符串的实际字符数据。如果字符串长度不超过 16 字符不包括终止符则直接存储在这个缓冲区中避免了堆内存的分配。mIsSSO:这是一个布尔值标志位用于表示当前字符串是否正在使用 SSO即字符串是否存储在mSSOBuffer中。如果mIsSSO为true则表示使用 SSO反之则表示使用堆内存。static_assert(sizeof(string) 48);解析这一行静态断言用于验证string类型的大小。如果该类型的大小与预期的 48 字节不同则会导致编译时错误。我们可以逐一计算string的大小mSize和mCapacity都是size_t类型在大多数系统中size_t是 8 字节64 位系统。所以它们占用的内存总大小是8 * 2 16字节。mData是一个指针指针通常占用 8 字节64 位系统。mSSOBuffer是一个固定大小的字符数组大小为 16 字节。mIsSSO是一个布尔值通常占用 1 字节但为了对齐可能会占用 8 字节取决于平台的内存对齐要求。因此string类型的总大小应该是16 ( mSize and mCapacity ) 8 ( mData ) 16 ( mSSOBuffer ) 8 ( mIsSSO ) 48 16 (\text{mSize and mCapacity}) 8 (\text{mData}) 16 (\text{mSSOBuffer}) 8 (\text{mIsSSO}) 4816(mSize and mCapacity)8(mData)16(mSSOBuffer)8(mIsSSO)48所以static_assert(sizeof(string) 48)确保了string类型在大多数 64 位系统中具有正确的大小。为什么要使用 SSOSmall String OptimizationSSO用于提高小字符串的性能因为内存分配小字符串的内存分配可以通过内嵌缓冲区避免对堆的频繁分配和释放减少性能开销。空间效率当字符串很短时将其存储在固定大小的缓冲区中如mSSOBuffer是更高效的因为这样避免了为每个小字符串分配堆内存。性能对于短字符串的操作如创建、复制、销毁避免了堆内存分配的开销通常能显著提升性能。总结这段代码实现了Small String Optimization (SSO)通过在string类型中使用一个固定大小的内嵌缓冲区来存储小字符串。只有当字符串的长度超过缓冲区的容量16 字节时才会使用堆内存。这种优化可以减少短字符串的内存分配开销提升性能。这段代码实现了Small String Optimization (SSO)目的是优化短字符串的存储以减少内存分配的开销。在这个实现中string类型根据字符串的长度动态地决定是否使用堆内存长字符串或将字符串存储在内嵌的缓冲区中短字符串。代码分析structstring{char*mPtr;// 指向字符串数据的指针size_t mSize{};// 字符串的大小即字符数不包括空终止符union{size_t mCapacity;// 如果字符串超过 SSO 容量使用堆内存时存储容量charmBuf[8];// 小字符串的缓冲区用于存储最多 7 个字符 1 个 \0 终止符};static_assert((sizeof(mBuf)sizeof(mPtr)sizeof(mSize))24);constexprstaticsize_tmax_cap(){returnstd::numeric_limitssize_t::max();}constexprstaticsize_tsso_cap(){returnsizeof(mBuf)-1;/* −1 for \0 */}constexprstaticboolfits_into_sso(size_t len){returnlensso_cap();}constexprboolis_long()const{returnmPtr!mBuf;}constexprstring():mPtr{mBuf},mBuf{}{}constexprstring(constchar*_data,size_t len):mPtr{fits_into_sso(len)?mBuf:newchar[len]},mSize{len},mBuf{}{if(is_long()){mCapacitylen;}// 如果使用堆内存则设置容量// 下一个步骤将 _data 复制到 mPtr}constexprsize_tsize()const{returnmSize;}constexprconstchar*data()const{returnmPtr;}constexprsize_tcapacity()const{returnis_long()?mCapacity:sso_cap();}};关键成员和函数解释成员变量:mPtr指向字符串数据的指针。对于短字符串它指向mBuf对于长字符串它指向堆内存。mSize表示字符串的大小即存储的字符数量不包括终止符。mCapacity和mBuf这两者使用union它们共享同一块内存。mBuf是一个固定大小的字符数组用于存储短字符串的内容mCapacity用于存储堆分配内存时的容量。静态断言:static_assert((sizeof(mBuf)sizeof(mPtr)sizeof(mSize))24);这条静态断言检查mBuf、mPtr和mSize的大小是否总和为 24 字节。在大多数 64 位系统中mBuf的大小为 8 字节mPtr是一个指针类型通常为 8 字节mSize是size_t类型也通常为 8 字节。所以它们的总大小应该是 24 字节。静态函数:max_cap()返回size_t的最大值。这个函数可以用于获取容量的上限。sso_cap()返回小字符串优化SSO缓冲区的最大容量。由于mBuf是一个大小为 8 字节的数组而其中最后一个字节用于存储字符串的终止符所以有效的容量是7字符。fits_into_sso(len)检查字符串的长度是否适合存储在 SSO 缓冲区中。即判断字符串长度是否小于等于 7 个字符sso_cap()。is_long()判断当前字符串是否存储在堆内存中。如果mPtr指向mBuf则表示是短字符串SSO否则是长字符串。构造函数:默认构造函数constexprstring():mPtr{mBuf},mBuf{}{}这是一个默认构造函数初始化时mPtr指向mBuf即表示当前字符串为空且存储在内嵌的缓冲区中。接受数据和长度的构造函数constexprstring(constchar*_data,size_t len):mPtr{fits_into_sso(len)?mBuf:newchar[len]},mSize{len},mBuf{}{if(is_long()){mCapacitylen;}}该构造函数接受一个const char* _data和字符串的长度len。如果字符串长度适合 SSO即不超过 7 个字符则将其存储在mBuf中否则分配堆内存来存储字符串。如果使用堆内存is_long()为true则设置mCapacity为字符串的长度。成员函数:size()返回字符串的大小。data()返回指向字符串数据的指针。capacity()返回字符串的容量。如果字符串存储在堆内存中返回mCapacity如果存储在 SSO 缓冲区中返回sso_cap()7 字符。SSO 设计说明小字符串优化SSO此实现的关键思想是对于较短的字符串最多 7 个字符直接将字符串存储在mBuf中而不进行堆内存分配。只有当字符串长度超过 SSO 限制时才会使用堆内存通过new操作分配。内存管理短字符串避免了内存分配和释放的开销提升了性能。对于长字符串堆内存依然可以提供足够的空间。总结该string类型实现了 Small String OptimizationSSO通过使用一个内嵌的固定大小缓冲区来存储小字符串减少内存分配开销提高性能。通过union来节省内存确保在短字符串情况下尽可能不使用额外内存。对于较长的字符串则通过堆内存存储。数学公式格式要求对于你的数学公式格式要求公式嵌入文字中例如mCapacity通常与sizeof(mBuf)相关可以通过公式表示为 $ mCapacity \approx \text{sizeof}(mBuf) $。公式单独一行SSO Cap 7 (characters, excluding null-terminator) \text{SSO Cap} 7 \quad \text{(characters, excluding null-terminator)}SSO Cap7(characters, excluding null-terminator)这段代码是Small String Optimization (SSO)的实现目的是通过将短字符串存储在对象内的一个固定大小缓冲区中从而避免频繁的内存分配减少内存开销。与前面的实现相比这个版本采用了union来在同一内存位置存储指针mPtr和内嵌缓冲区mBuf。让我们逐步分析每个部分的实现。代码分析structstring{union{char*mPtr;// 长字符串的堆内存指针charmBuf[8];// 小字符串的内嵌缓冲区};size_t mSize{};// 字符串的实际大小不包括终止符size_t mCapacity{};// 字符串的容量static_assert((sizeof(mBuf)sizeof(mCapacity)sizeof(mSize))24);constexprstaticsize_tmax_cap(){returnstd::numeric_limitssize_t::max();}constexprstaticsize_tsso_cap(){returnsizeof(mBuf)-1;/* −1 for \0 */}constexprstaticboolfits_into_sso(size_t len){returnlensso_cap();}constexprboolis_long()const{returnmCapacitysso_cap();}constexprstring():mBuf{}{}constexprstring(constchar*_data,size_t len):mBuf{},mSize{len},mCapacity{fits_into_sso(len)?sso_cap():len}{if(is_long()){mPtrnewchar[len];}// copy _data to mPtr or mBuf}constexprsize_tsize()const{returnmSize;}constexprconstchar*data()const{returnis_long()?mPtr:mBuf;}constexprsize_tcapacity()const{returnmCapacity;}};各个部分的详细解释1.成员变量:mPtr和mBuf:使用了union意味着mPtr和mBuf共享相同的内存空间。mPtr是指针类型用于存储指向堆内存的指针存储较长的字符串mBuf是一个字符数组用于存储短字符串。mBuf的大小为 8 字节因此它最多可以存储 7 个字符留一个字节给字符串的空字符\0。mSize:表示字符串的实际大小不包括终止符即字符串的字符数。mCapacity:字符串的容量表示可以容纳的字符数。对于使用 SSO 存储的短字符串mCapacity设置为sso_cap()即 7而对于长字符串mCapacity是堆内存的长度。2.静态断言:static_assert((sizeof(mBuf)sizeof(mCapacity)sizeof(mSize))24);这行代码确保mBuf8 字节、mCapacitysize_t8 字节和mSizesize_t8 字节的总大小为 24 字节符合对内存布局的要求。在 64 位系统上size_t通常占用 8 字节因此mBuf占用 8 字节mCapacity和mSize各占用 8 字节总大小应为 24 字节。3.静态成员函数:max_cap():返回size_t的最大值表示容量的最大值。sso_cap():返回小字符串优化SSO缓冲区的容量。由于mBuf是 8 字节且留出一个字节存储空字符\0所以最大存储容量是 7 个字符。fits_into_sso(len):判断字符串的长度len是否适合存储在 SSO 缓冲区中。如果字符串的长度小于或等于sso_cap()即 7 字符则返回true否则返回false。is_long():判断当前字符串是否为长字符串。如果mCapacity大于sso_cap()则表示使用堆内存存储字符串属于长字符串。4.构造函数:默认构造函数:constexprstring():mBuf{}{}默认构造函数将字符串初始化为空并将数据存储在mBuf中。接受数据和长度的构造函数:constexprstring(constchar*_data,size_t len):mBuf{},mSize{len},mCapacity{fits_into_sso(len)?sso_cap():len}{if(is_long()){mPtrnewchar[len];}// copy _data to mPtr or mBuf}如果字符串长度小于等于sso_cap()即 7 字符则将数据存储在内嵌缓冲区mBuf中如果字符串长度超过 7 个字符则使用new动态分配堆内存并将mPtr指向堆内存mCapacity会设置为字符串的长度如果是长字符串。5.成员函数:size():返回字符串的大小即字符数不包括\0终止符。data():返回一个指向字符串数据的指针。如果是短字符串SSO返回mBuf否则返回mPtr堆内存指针。capacity():返回字符串的容量。如果是短字符串返回sso_cap()如果是长字符串返回mCapacity。关键优化Small String Optimization (SSO):对于长度不超过 7 个字符的字符串直接存储在内嵌缓冲区mBuf中避免了堆内存分配提升了性能。内存优化:通过union使得mPtr和mBuf共享内存空间在短字符串情况下避免了额外的内存分配。堆内存使用:当字符串长度大于 7 个字符时使用堆内存存储数据允许存储更长的字符串。数学公式SSO 缓冲区容量对于短字符串最大字符数是7 77因为最后一个字节用于存储空字符\0。公式如下SSO capacity 7 \text{SSO capacity} 7SSO capacity7容量判定对于长字符串使用堆内存时容量等于字符串的长度capacity len \text{capacity} \text{len}capacitylen总结这个string类型实现了 Small String OptimizationSSO通过内嵌的缓冲区mBuf存储短字符串以避免堆内存分配。当字符串长度超过 7 个字符时使用堆内存存储数据。通过union共享内存空间减少内存开销同时保证了短字符串和长字符串的高效存储。这段代码展示了Small String Optimization (SSO)的实现采用了位域bit-fields和联合体union来优化内存的使用。与之前的实现相比它通过位域来存储更多信息如是否是长字符串、字符串的大小、容量等同时通过内存填充来确保内存对齐和优化空间利用。接下来我们将详细解析这段代码。代码结构和各个部分的解析structstring{staticconstexprunsignedBIT_FOR_CAP{sizeof(size_t)*8-1};// 容量位字段的位数// 长字符串的存储结构structnormal{size_t large:1;// 用 1 位表示是否是长字符串size_t capacity:BIT_FOR_CAP;// 容量使用位域size_t size;// 字符串大小char*data;// 数据指针};// 短字符串的存储结构structsso{uint8_tlarge:1;// 用 1 位表示是否是长字符串uint8_tsize:(sizeof(uint8_t)*8)-1;// 字符串大小剩余的位uint8_tpadding[sizeof(size_t)-sizeof(uint8_t)];// 填充使结构体大小对齐chardata[sizeof(normal)-sizeof(size_t)];// 存储短字符串的数据};union{sso small;// 短字符串使用 sso 结构normal large;// 长字符串使用 normal 结构}packed;// 静态断言确保 normal 和 sso 的大小一致且为 24 字节static_assert((sizeof(normal)sizeof(sso))and(sizeof(normal)24));// 获取最大容量staticsize_tmax_cap(){returnstd::pow(2,BIT_FOR_CAP);}// 获取 SSO 的容量除去空字符constexprstaticsize_tsso_cap(){returnsizeof(sso::data)-1;}// 判断字符串是否可以存储在 SSO 缓冲区中constexprstaticboolfits_into_sso(size_t len){returnlensso_cap();}// 判断字符串是否是长字符串constexprboolis_long()const{returnpacked.small.large;}// 默认构造函数constexprstring():packed{}{}// 带数据和长度的构造函数constexprstring(constchar*_data,size_t len):packed{}{if(fits_into_sso(len)){packed.small.sizelen;// 短字符串直接存储大小}else{packed.large.largetrue;// 长字符串设置为长字符串packed.large.sizelen;// 设置大小}// 复制数据到 data()}// 获取字符串大小constexprsize_tsize()const{returnis_long()?packed.large.size:packed.small.size;}// 获取字符串数据constexprconstchar*data()const{returnis_long()?packed.large.data:packed.small.data;}// 获取字符串容量constexprsize_tcapacity()const{returnis_long()?packed.large.capacity:sso_cap();}};主要部分分析1.静态常量BIT_FOR_CAP:staticconstexprunsignedBIT_FOR_CAP{sizeof(size_t)*8-1};这定义了一个静态常量BIT_FOR_CAP它表示容量位字段capacity的位数。sizeof(size_t)返回size_t类型的字节数而* 8是将字节转换为位数减去 1 是因为需要一个位来存储large字段剩余的位用于存储capacity字段。2.normal结构长字符串存储:structnormal{size_t large:1;size_t capacity:BIT_FOR_CAP;size_t size;char*data;};large用 1 位表示当前字符串是否为长字符串如果是长字符串large为 1否则为 0。capacity表示字符串的容量使用BIT_FOR_CAP位来存储。由于large占用了 1 位capacity可以使用剩余的位来表示字符串的容量。size表示字符串的大小即字符数不包括\0。data指向堆内存中存储字符串数据的指针。3.sso结构短字符串存储:structsso{uint8_tlarge:1;uint8_tsize:(sizeof(uint8_t)*8)-1;uint8_tpadding[sizeof(size_t)-sizeof(uint8_t)];chardata[sizeof(normal)-sizeof(size_t)];};large同样是用 1 位表示是否为长字符串。size表示字符串的大小使用剩余的位来存储字符串长度size_t的位数减去1位用于large字段。padding用于填充内存确保结构体的大小对齐为size_t的大小。data存储短字符串的实际数据它的大小等于normal结构的大小减去size_t的大小从而确保内存布局和对齐。4.union packed:union{sso small;normal large;}packed;union用于存储small短字符串和large长字符串根据字符串的长度动态决定使用哪个结构。union保证了短字符串和长字符串共享同一块内存因此节省内存。5.static_assert:static_assert((sizeof(normal)sizeof(sso))and(sizeof(normal)24));这个静态断言确保normal和sso结构体的大小相同并且它们的大小为 24 字节。这是为了确保内存布局一致。6.静态函数和成员函数:max_cap()返回容量的最大值使用std::pow(2, BIT_FOR_CAP)计算。sso_cap()返回 SSO 的最大容量减去 1 字节存储空字符。fits_into_sso(len)判断给定的字符串长度是否适合存储在 SSO 缓冲区中。is_long()判断字符串是否为长字符串即large字段为1。构造函数根据字符串长度来决定是使用 SSO 还是堆内存。若长度小于等于sso_cap()则使用 SSO 存储否则使用堆内存。size()、data()和capacity()返回字符串的大小、数据和容量。根据字符串的类型短字符串或长字符串来返回对应的值。数学公式容量位字段的位数BIT_FOR_CAP sizeof ( s i z e _ t ) × 8 − 1 \text{BIT\_FOR\_CAP} \text{sizeof}(size\_t) \times 8 - 1BIT_FOR_CAPsizeof(size_t)×8−1SSO 缓冲区的最大容量SSO Capacity sizeof ( s s o : : d a t a ) − 1 \text{SSO Capacity} \text{sizeof}(sso::data) - 1SSO Capacitysizeof(sso::data)−1总结该string类型实现了Small String Optimization (SSO)通过位域和联合体来优化内存使用对于短字符串长度小于等于 SSO 缓冲区的容量直接使用内嵌缓冲区data存储数据对于长字符串使用堆内存通过normal结构存储字符串内容。该实现有效地节省了内存并提高了短字符串的性能同时通过位域和联合体确保了内存对齐和空间的最大利用。这段代码展示了Small String Optimization (SSO)的另一种实现称为fbstring其中通过使用联合体union和位运算来优化内存存储。它和前面几种实现的差异主要体现在内存对齐、容量的虚拟减少以及通过位操作来区分短字符串和长字符串。让我们逐步分析每个部分。代码解析structstring{structnormal{char*data;// 用于长字符串的数据指针size_t size;// 字符串的大小不包括空终止符size_t capacity;// 字符串的容量为便于简化减少了 1 字节的容量};structsso{chardata[sizeof(normal)];// 短字符串存储容量空间与 normal 结构相同};union{sso small;// 短字符串使用 sso 结构normal large;// 长字符串使用 normal 结构}packed;static_assert((sizeof(normal)sizeof(sso))and(sizeof(normal)24));staticsize_tmax_cap(){returnstd::pow(2,sizeof(normal::capacity)*8-8);}constexprstaticsize_tsso_cap(){returnsizeof(sso)-1;}constexprcharget_mode_byte(){returnpacked.small.data[sizeof(normal)-1];}constexprcharget_mode_byte()const{returnpacked.small.data[sizeof(normal)-1];}constexprstaticboolfits_into_sso(size_t len){returnlensso_cap();}constexprboolis_long()const{returnget_mode_byte()0x40;/* 0b1000000 */}// 默认构造函数constexprstring():packed{}{}// 构造函数根据数据长度选择使用 SSO 还是堆内存constexprstring(constchar*_data,size_t len):packed{}{if(fits_into_sso(len)){get_mode_byte()sso_cap()-len;// A. 剩余字节数存储在 mode 字节中}else{get_mode_byte()0x40;// B. 设置标志位表示长字符串模式packed.large.sizelen;// 长字符串存储大小}// 将数据复制到 data}// 获取字符串大小constexprsize_tsize()const{returnis_long()?packed.large.size:sso_cap()-get_mode_byte();}// 获取字符串数据constexprconstchar*data()const{returnis_long()?packed.large.data:packed.small.data;}// 获取字符串容量constexprsize_tcapacity()const{returnis_long()?packed.large.capacity:sso_cap();}};关键部分分析1.normal结构长字符串:structnormal{char*data;// 存储堆内存中的字符串数据size_t size;// 字符串的大小size_t capacity;// 字符串的容量};data指向堆内存的指针用于存储长字符串。size表示字符串的实际大小不包括终止符\0。capacity表示字符串的容量存储可以容纳的字符数。这里容量可能被虚拟地减少 1 字节通过sizeof(normal)进行对齐操作。2.sso结构短字符串:structsso{chardata[sizeof(normal)];// 短字符串的存储结构容量与 normal 结构相同};data这是一个字符数组大小与normal结构相同存储短字符串数据。这里通过对normal结构进行内存对齐确保短字符串的存储空间和长字符串的结构一致。3.union packed:union{sso small;// 短字符串normal large;// 长字符串}packed;这个联合体packed共享内存其中small用于存储短字符串数据large用于存储长字符串数据。通过union短字符串和长字符串共享同一块内存从而节省内存空间。4.静态断言:static_assert((sizeof(normal)sizeof(sso))and(sizeof(normal)24));这个静态断言确保normal和sso结构的大小相同并且它们的大小为 24 字节。这个大小通常是为了在 64 位系统上进行内存对齐和优化。5.max_cap():staticsize_tmax_cap(){returnstd::pow(2,sizeof(normal::capacity)*8-8);}这个函数返回normal::capacity可以表示的最大值。由于capacity是size_t类型这个函数计算了size_t类型可以表示的最大容量。6.sso_cap():constexprstaticsize_tsso_cap(){returnsizeof(sso)-1;}sso_cap()函数返回 SSO 缓冲区的容量。由于sso中的最后 1 字节用于存储mode字节实际可用容量是sizeof(sso) - 1。7.get_mode_byte():constexprcharget_mode_byte(){returnpacked.small.data[sizeof(normal)-1];}这个函数返回mode字节即packed.small.data的最后一个字节。这个字节用于标识字符串是短字符串还是长字符串。get_mode_byte()可以获取该字节并允许我们设置或读取该字节的值。8.is_long():constexprboolis_long()const{returnget_mode_byte()0x40;}该函数判断字符串是否是长字符串。如果mode字节的高位0x40为 1则表示这是一个长字符串。9.构造函数:默认构造函数constexprstring():packed{}{}该构造函数将packed初始化为空即small和large都没有数据。带数据的构造函数constexprstring(constchar*_data,size_t len):packed{}{if(fits_into_sso(len)){get_mode_byte()sso_cap()-len;// A}else{get_mode_byte()0x40;// Bpacked.large.sizelen;}// 将数据复制到 data()}如果字符串可以存储在 SSO 缓冲区中则将mode字节设置为剩余字节数sso_cap() - len即可用的空间。如果字符串过长则将mode字节的高位设置为 10x40表示长字符串模式并将数据存储在堆内存中。10.成员函数:size()返回字符串的大小。对于长字符串返回packed.large.size对于短字符串返回sso_cap() - get_mode_byte()。data()返回字符串数据。根据字符串是否为长字符串选择从packed.large.data或packed.small.data中返回数据。capacity()返回字符串的容量。如果是长字符串返回packed.large.capacity否则返回sso_cap()。数学公式SSO 缓冲区的容量SSO Capacity sizeof ( s s o ) − 1 \text{SSO Capacity} \text{sizeof}(sso) - 1SSO Capacitysizeof(sso)−1最大容量max_cap() 2 ( sizeof ( n o r m a l : : c a p a c i t y ) × 8 ) − 8 \text{max\_cap()} 2^{(\text{sizeof}(normal::capacity) \times 8) - 8}max_cap()2(sizeof(normal::capacity)×8)−8总结这个string类型实现了Small String Optimization (SSO)通过使用联合体union和位操作来有效地存储短字符串和长字符串对于短字符串使用一个内嵌的缓冲区存储数据并通过mode字节指示字符串的长度。对于长字符串使用堆内存存储数据并通过位域标识是否是长字符串。这段代码展示了几个 C 特性的应用包括constexpr的使用、std::initializer_list、以及通过模板和初始化列表实现的一些模式。我们将逐步解析各个部分并详细讲解其原理。代码解析1.FixedString类templatesize_t NclassFixedString{size_t mSize{};// 字符串的大小charmData[N]{};// 固定大小的字符数组public:FixedString()default;// 默认构造函数FixedString(constchar*str):mSize{std::char_traitschar::length(str)}{std::copy_n(str,size(),mData);// 将字符串复制到 mData 中}size_tsize()const{returnmSize;}// 获取字符串的大小std::string_viewdata()const{return{mData,mSize};}// 获取字符串数据};FixedString类模板定义了一个模板类FixedString它接受一个模板参数N表示字符串的最大长度。mSize存储字符串的实际大小。mData固定大小的字符数组用于存储字符串内容。数组的大小由N决定。默认构造函数和带字符串构造函数如果传入一个字符串则计算字符串的大小并将其内容复制到mData中。构造函数FixedString(const char* str)接受一个 C 风格的字符串将其长度存储在mSize中并通过std::copy_n将字符串内容复制到mData中。成员函数size()返回字符串的大小。data()返回字符串数据使用std::string_view包装mData和mSize使得它可以作为一个不可修改的视图来访问。2.make_fixed_string函数模板templatesize_t Nautomake_fixed_string(constchar(str)[N]){returnFixedStringN{str};// 根据输入字符串创建 FixedString 对象}make_fixed_string这是一个函数模板用于通过一个字面量 C 风格字符串来创建一个FixedString实例。它使用模板参数推导自动推断字符串的大小N。该函数将传入的 C 风格字符串如Hello, embedded World!传递给FixedString的构造函数返回一个新的FixedString对象。3.常量FixedString对象conststaticFixedString50x{Hello, embedded World!};conststaticautoy{make_fixed_string(Hello, some other planet!)};x是一个静态常量的FixedString对象最大容量为 50存储字符串Hello, embedded World!。y是通过make_fixed_string函数模板创建的FixedString对象字符串是Hello, some other planet!编译器通过模板参数推导自动推断FixedString的大小。4.std::initializer_list使用示例voidFun(){std::initializer_listintlist{3,4,5,6};Receiver(list);}std::initializer_list这是一个标准库模板类允许你使用花括号{}初始化一组元素并将其作为一个常量列表传递。initializer_list是一个容器它提供对容器中的元素的只读访问。这里list初始化了包含四个整数的列表{3, 4, 5, 6}并将其传递给Receiver函数。5.Receiver函数重载voidReceiver(constintlist[4])noexcept;voidReceiver(std::initializer_listintlist)noexcept;Receiver(const int list[4])这是接收一个大小为 4 的整数数组的函数。Receiver(std::initializer_listint list)这是接收一个initializer_list类型的函数它与数组不同可以用于接收动态大小的列表。6.使用static和noexcept修饰符voidFun()noexcept{staticconstintlist[4]{3,4,5,6};Receiver(list);}static将list声明为静态数组表示该数组在函数调用之间保持其值。noexcept表示该函数不会抛出异常。这是 C11 引入的特性有助于编译器优化和确保异常安全性。7.总结不同版本的FunvoidFun()noexcept{std::initializer_listintlist{3,4,5,6};Receiver(list);}voidFun()noexcept{constintlist[4]{3,4,5,6};Receiver(list);}voidFun()noexcept{staticconstintlist[4]{3,4,5,6};Receiver(list);}第一种形式使用了std::initializer_listint来传递列表。第二种形式使用了传统的 C 数组固定大小为 4来传递数据。第三种形式使用了static关键字使得list成为静态数组它的生命周期贯穿于程序的运行期。数学公式在这段代码中没有明显的数学公式但我们可以简化一些运算的解释size_t N表示固定字符串的长度模板的参数N确定了固定字符串数组的大小。std::copy_n(str, size(), mData)表示从str中复制size()个字符到mData中。这里size()是字符串的实际大小不包括空字符。总结这段代码展示了 C 中的一些常见特性和技术constexpr使得常量字符串的大小可以在编译时确定优化了性能。std::initializer_list允许使用花括号{}语法来初始化容器可以用于处理固定集合的元素。模板与推导使用模板和类型推导如make_fixed_string来动态生成固定大小的字符串容器。static和noexcept确保数据在函数调用之间保持不变并且函数没有异常抛出。以下是一个完整的 C 示例展示了constexpr、FixedString类、std::initializer_list以及如何使用模板推导来处理固定长度的字符串和初始化列表#includeiostream#includestring_view#includealgorithm#includeinitializer_list#includeiteratortemplatesize_t NclassFixedString{size_t mSize{};// 字符串的实际大小charmData[N]{};// 固定大小的字符数组public:// 默认构造函数FixedString()default;// 从C风格字符串构造FixedString(constchar*str):mSize{std::char_traitschar::length(str)}{std::copy_n(str,size(),mData);// 复制字符到 mData}// 获取字符串的大小size_tsize()const{returnmSize;}// 返回字符串数据std::string_viewdata()const{return{mData,mSize};}};// 函数模板根据输入的字符串创建 FixedStringtemplatesize_t Nautomake_fixed_string(constchar(str)[N]){returnFixedStringN{str};}// 接收 std::initializer_list 的函数voidReceiver(std::initializer_listintlist)noexcept{std::coutReceiver called with list: ;for(constautoitem:list){std::coutitem ;}std::coutstd::endl;}// 示例创建常量字符串对象conststaticFixedString50x{Hello, embedded World!};conststaticautoy{make_fixed_string(Hello, some other planet!)};// 使用 std::initializer_list 示例voidFun(){std::initializer_listintlist{3,4,5,6};// 创建初始化列表Receiver(list);}// 另一种接收固定大小数组的函数voidReceiver(constintlist[4])noexcept{std::coutReceiver called with array: ;for(size_t i0;i4;i){std::coutlist[i] ;}std::coutstd::endl;}// 另一种接收固定数组的方法voidFun2()noexcept{staticconstintlist[4]{3,4,5,6};// 固定大小的数组Receiver(list);// 传递数组}intmain(){// 测试 FixedString 类std::coutFixedString x: x.data(), size: x.size()std::endl;std::coutFixedString y: y.data(), size: y.size()std::endl;// 使用 std::initializer_listFun();// 使用固定大小数组Fun2();return0;}解释FixedString类FixedString是一个模板类它使用固定大小的字符数组mData[N]来存储字符串并且可以通过构造函数从 C 风格字符串const char*初始化。它有size()和data()成员函数分别用于返回字符串的大小和数据。在FixedString类的构造函数中我们使用std::char_traitschar::length(str)来计算字符串的长度并将其复制到mData数组中。make_fixed_string函数模板这是一个函数模板接受一个 C 风格字符串字面量并返回一个FixedString对象。编译器会根据传入的字符串大小自动推导N。std::initializer_list示例在Fun()和Fun2()函数中我们展示了如何使用std::initializer_list来初始化一个整数列表并将其传递给Receiver函数。Receiver函数接收一个std::initializer_listint或者一个固定大小的数组const int[4]并通过循环打印其中的元素。Receiver函数Receiver函数展示了如何接收std::initializer_list和固定大小的数组。通过std::initializer_list我们可以灵活地传递任何大小的列表而固定大小的数组要求元素个数在函数定义时已知。输出示例FixedString x: Hello, embedded World!, size: 22 FixedString y: Hello, some other planet!, size: 25 Receiver called with list: 3 4 5 6 Receiver called with array: 3 4 5 6第一个输出显示了FixedString对象x和y的字符串内容和大小。接下来是Receiver函数的输出它从std::initializer_list和固定数组中接收数据并打印。总结这个完整的例子展示了如何使用 C11 及以上版本中的constexpr、模板、std::initializer_list和类型推导来实现高效的内存管理、字符串处理和数组传递。通过FixedString类可以处理固定大小的字符串而std::initializer_list提供了一种灵活的方式来处理多个元素。通过几个具体例子说明C 中字符串和\0的关系让概念更清晰。例 1std::string默认情况#includeiostream#includecstringintmain(){std::string sHello;std::couts.size() s.size()std::endl;std::couts.c_str() s.c_str()std::endl;std::coutstrlen(s.c_str()) std::strlen(s.c_str())std::endl;return0;}输出s.size() 5 s.c_str() Hello strlen(s.c_str()) 5解释s.size()返回字符串长度不包含末尾的\0。c_str()返回 C 风格字符串内部有一个隐式的\0结尾。strlen(c_str())也不算\0。例 2字符串中显式包含\0#includeiostream#includestringintmain(){std::string s1std::string(Hi\0World,8);// 手动指定长度std::string s2std::string(Hi World);std::couts1.size() s1.size()std::endl;std::couts2.size() s2.size()std::endl;for(charc:s1){std::coutint(c) ;// 输出字符的 ASCII 值}std::coutstd::endl;for(charc:s2){std::coutint(c) ;// 输出字符的 ASCII 值}std::coutstd::endl;std::couts1.c_str() s1.c_str()std::endl;std::couts2.c_str() s2.c_str()std::endl;return0;}输出s1.size() 8 s2.size() 8 72 105 0 87 111 114 108 100 72 105 32 87 111 114 108 100 s1.c_str() Hi s2.c_str() Hi World解释中间的\0被计入字符串大小。s.size()返回 8。遍历字符串可以看到 ASCII 码 0 对应\0。例 3std::string_view包含\0#includeiostream#includestring_viewintmain(){constchararr[]{A,\0,B,\0};std::string_viewsv(arr,4);// 显式指定长度std::coutsv.size() sv.size()std::endl;for(charc:sv){std::coutint(c) ;// 输出字符的 ASCII 值}std::coutstd::endl;return0;}输出sv.size() 4 65 0 66 0解释string_view可以包含任意字符包括中间的\0。size()返回全部字符数量包括\0。总结规律类型是否包含\0size()是否算\0std::string内部有隐式末尾\0不算末尾的\0std::string显式包含\0可以包含任意\0算在size()中std::string_view视图范围内的所有字符都算包括中间的\0C 风格字符串必须以\0结尾strlen() 不算\0如果你愿意我可以画一张内存布局图直观地展示std::string、string_view、和 C 风格字符串中\0的位置和size()计数方式让概念更清楚。
版权声明:本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!

学习网站建设有什么用汕头做网站优化哪家好

Apache SeaTunnel终极实战指南:3步掌握高效数据集成运维 【免费下载链接】seatunnel 项目地址: https://gitcode.com/gh_mirrors/seat/seatunnel Apache SeaTunnel作为新一代数据集成平台,正在成为企业数据架构的核心组件。本文将从零开始&#…

张小明 2025/12/28 19:26:54 网站建设

怎么做百度采购网站做暧暧前戏视频网站

YOLO目标检测服务支持审计日志导出 在智能制造车间的边缘服务器上,一个YOLO模型正以每秒200帧的速度分析产线视频流。突然,系统告警:某时段检测准确率异常下降5%。运维人员并未重启服务,而是打开后台控制台,点击“导出…

张小明 2025/12/28 19:26:20 网站建设

深圳福田区区住房和建设局网站中国新闻社官方网站

探索Chota:3KB极简CSS框架的无限可能 【免费下载链接】chota A micro (3kb) CSS framework 项目地址: https://gitcode.com/gh_mirrors/ch/chota 还在为复杂CSS框架的臃肿而烦恼吗?Chota——这个仅有3KB的轻量级CSS框架,正以其极简设计…

张小明 2025/12/28 19:24:40 网站建设

微信手机网站制作外贸企业网络推广

数字人情绪迁移技术:Linly-Talker如何实现表情控制? 在虚拟主播深夜开播、AI客服主动安抚用户情绪的今天,数字人早已不再是影视特效中的“奢侈品”。它们正以惊人的速度渗透进直播、教育、金融等日常场景。但问题也随之而来:一个只…

张小明 2025/12/28 19:22:59 网站建设

建立网站需要多少钱多少钱28湖南岚鸿晋江怎么交换友情链接

文章目录前言1.关于Netdata2.本地部署Netdata3.使用Netdata4.cpolar内网穿透工具安装5.创建远程连接公网地址6.固定Netdata公网地址前言 Netdata 是一款实时监控服务器性能的工具,能实时追踪 CPU、内存、磁盘 IO 等上万项指标,适合服务器管理员、运维人…

张小明 2025/12/28 19:22:24 网站建设