C++17中的constexpr static

constexpr用于声明编译时常量,确保在编译时初始化,优化性能并解决模板参数等问题。inline主要解决头文件中函数或变量的多重定义问题,但.cpp文件中通常不需要。全局和静态变量的初始化顺序可能导致问题,constexpr能确保编译时初始化,消除不确定性。C++17引入inline变量,允许在多个翻译单元间共享且只初始化一次,解决了全局变量的链接和初始化问题。
摘要由CSDN通过智能技术生成

constexpr是C++的一个关键字,它用于声明编译时常量。
当constexpr用来修饰函数、对象摘要或对象声明时,这意味着函数或对象的值在编译期间就可以确定。这样可以在编译时进行一些优化,也可用于其他要求编译时确定值的场合。
如果不使用constexpr,不能保证在编译期间就是字面值常量。例如作为模板参数。
会在运行时计算的话会影响性能。

在.cpp文件或者一些实现文件中,通常不需要将变量标记为inline。
inline关键字主要用于解决头文件 (.h 或 .hpp 文件) 中定义的函数或变量在多个源文件 (.cpp 文件) 中被包含时,可能会引起的多重定义问题。因为头文件在每个包含它的.cpp文件中都会被编译一次,如果头文件中有变量或函数的定义,那么就会在每个.cpp文件中都生成该变量或函数的定义,导致链接时出现多重定义错误。使用inline就可以避免这样的问题,在链接时,编译器会保证同一个inline变量或函数在所有的.cpp文件中只有一个实例。
但在.cpp文件中,变量或函数的定义只会出现一次,所以不存在多重定义的问题,就没有必要使用inline。在.cpp文件中使用inline可能会导致代码的可读性降低,并且可能会影响编译器的优化决策(例如,编译器可能会决定不进行内联,这可能影响执行性能)。所以,除非有特别的理由,否则通常在.cpp文件中不用将变量标记为inline。

const可以在运行时进行初始化,而constexpr则必须在编译时进行初始化。
使用constexpr可以保证初始化和销毁的安全性。
这句话的意思是,通过使用constexpr,可以确保在编译时就初始化变量,这样做可以避免运行时的初始化顺序问题。这对于全局变量或者静态变量来说非常重要,因为这些变量的初始化顺序在运行时往往是不确定的。
此外,constexpr变量只能初始化为编译时常量,这意味着它们的值不能改变,所以也就没有销毁的问题。也就是说,constexpr变量在整个程序执行过程中都是存在的,不会因为退出某个函数或者某个代码块而被销毁。这可以避免因为变量的提前销毁而导致的一些运行时错误。

全局变量:程序开始时创建,程序结束时销毁,作用域是从定义位置开始到文件结束。不同类型的全局变量有不同的默认初始值。int 0 bool false 指针 null 类类型 默认构造

静态变量:函数内部和函数外部,本身静态变量就是为了隐藏全局变量,并且函数内部定义的静态变量,作用域在所在函数,第一次调用时初始化,结束时销毁,没定义时默认为0,函数外部的类似于全局变量,但是对于其他文件不可见。

C++的全局变量和静态变量的初始化顺序问题是比较让人头疼的一个地方,原因在于C++标准规定:
在同一个编译单位(同一个源文件及其包含的头文件)内,全局变量和静态变量的初始化顺序与定义顺序相同。
不同编译单位中全局变量和静态变量的初始化顺序是未定义的。
这就可能引发一些问题。假设有两个全局变量A和B,B在初始化时依赖于A已经完成初始化。如果A和B定义在同一个文件中,并且A在B之前定义,那么一切都不会有问题。但如果A和B定义在不同的文件中,那么可能出现A在B之后初始化的情况,而B在初始化时又会试图使用A,那么就会引发运行时错误。
通过对全局变量和静态变量使用constexpr,可以确保其是编译时常量,会在编译阶段进行初始化,从而避免这种初始化顺序的不确定性带来的问题。

inline修饰变量、#pragma once指令以及防卫式声明,都是C++中为了解决包含头文件导致的重复定义及重复编译的问题所提出的解决方案。
inline修饰变量:在C++17中,inline关键字不再仅用于函数,还可以用于修饰全局变量。被inline修饰的全局变量,在多个源文件中只会有一个实例,也就是说多个源文件中的同名inline变量实际上是同一个变量,这就避免了重复定义的问题。
#pragma once:这是一种预处理指令,用于防止头文件的内容在同一份源文件中被包含多次。当预处理器看到#pragma once时,会检查当前文件是否已经被包含过,如果已经被包含过,则会忽略该文件的剩余部分。这样就可以避免编译器重复编译同一个头文件,提高编译效率。
防卫式声明:又称为包含卫士或头文件保护,在防卫式声明中,通常会在头文件的开始和结束分别添加#ifndef, #define和#endif这三个预处理指令。它们配合使用可以防止头文件的内容被重复包含和编译,避免因此导致的重复定义错误。
尽管这三者的实现机制存在差异,但他们的目标都是一致的,即尽量减少因重复包含头文件而引发的问题。

struct S_CXX17_string{
const static std::string kHelloWorld;
};
const std::string S_CXX17_string::kHelloWorld = “Hello World.”;
这个变量在运行时也是不可修改的。
// 建议设置为static 没有用到其他的变量
static constexpr std::string_view HelloWorld()
{
return “Hello World1().”;
}
在C++17中,inline变量和static变量之间的主要区别在于它们的链接属性和初始化行为。
inline变量:C++17新增了inline变量,允许在多个翻译单元之间共享相同的变量。并且保证了变量在程序中只被初始化一次。inline变量必须在声明时进行定义。inline变量的链接属性是外部的,这意味着在程序的任何地方都可以访问这个变量。

static变量:在函数或类的内部声明的static变量在整个程序的生命周期内只初始化一次。在函数内部,这意味着变量在首次进入函数时初始化,然后在后续的函数调用中保留其值。在类中,这意味着所有类的实例共享同一个静态成员变量。静态变量可以有内部链接属性(在同一翻译单元内可见)或外部链接属性(在全程序范围内可见),这取决于它们是在全局范围内还是在类或函数内部声明的。
总的来说,inline变量是在多个翻译单元之间共享变量的解决方案,而static变量是用于在函数调用之间或在类的实例之间维护状态的解决方案。

在C++17中,inline变量和全局变量之间的主要区别在于它们的链接和初始化。
inline变量:C++17新增了inline变量,允许在多个翻译单元之间共享相同的变量。并且保证了变量在整个程序中只被初始化一次。inline变量必须在声明时进行定义。它的链接属性是外部的,这意味着在程序的任何地方都可以访问这个变量。
全局变量:全局变量在整个程序中都是可见的,并且在程序的生命周期内只初始化一次。全局变量默认在定义时就被初始化,如果没有显式地初始化,它们的值将被初始化为零。全局变量的链接属性可以是内部的,也可以是外部的,这取决于是否使用了extern关键字。
总的来说,inline变量是在多个翻译单元之间共享变量的解决方案,而全局变量主要用于在程序的全局范围内共享或维护状态。

在C++中,翻译单元是指源代码文件加上它所包含的所有头文件。编译器的工作就是将每个翻译单元翻译成一个目标文件。翻译单元也被认为是编译器在编译程序时的一个单元。
如果有一个源文件main.cpp,它包含了几个头文件,那么编译器将整个main.cpp和它所包含的头文件看作一个单独的翻译单元。
在一个翻译单元中,所有的全局和静态变量只被定义一次,所有的函数也只被编译一次。
所以当我们说“C++17新增了inline变量,允许在多个翻译单元之间共享相同的变量”时,我们的意思是,使用inline关键字可以让同一变量在多个源文件(翻译单元)之间共享。

Inline 一个cpp和与他相关的.h 多个翻译单元之间共享 只要定义完全相同就能重复定义且保证初始化的唯一性(程序开始就初始化,且只初始化一次,普通全局变量编译完了,发现不同文件的同名变量不相同,才会报链接错误)
全局变量 本cpp,使用extern可用于其他的cpp 不能重复定义
Static:类内的或者本cpp内 本翻译单元内部(局部静态变量是按需初始化)

在C++程序中,所有全局变量(包括inline全局变量和普通全局变量)的初始化都是在main函数开始执行前完成的。普通全局变量的初始化也是在程序启动时进行,也只会初始化一次。这一点和inline全局变量是一样的。当在引述inline全局变量"确保只初始化一次"的特性时,主要是针对在不同编译单元进行定义的情况。因为inline全局变量可以在多个编译单元中定义,但所有的定义必须完全相同,编译器会确保它们引用的是同一个对象,同时也确保这个对象只进行了一次初始化。
而对于普通全局变量,如果在不同编译单元定义了同名全局变量,会造成链接错误。每个编译单元中的全局变量都会进行一次初始化。
所以"确保只初始化一次"这一特性,更多的是为了解决在不同编译单元定义同名全局变量的问题。

在C++中,static关键字为变量或函数提供了内部链接。当一个变量在文件范围内被声明为static时,它只能在定义它的源文件中被访问。它对于其他的源文件是不可见的,即使这个源文件包含了定义该变量的源文件的头文件。
所以,答案是不能的。在一个cpp文件中声明的static变量不能在相关的头文件中被访问,也不能在其他任何源文件中被访问。这就是static关键字通常用来隐藏与具体实现相关的细节。
例如:
// file1.cpp
static int x = 0;
在这种情况下,变量x只能在file1.cpp中被访问,不能在任何其他源文件中被访问,即使这个源文件包含了file1.cpp的头文件。
如果你想要在一个源文件中定义一个变量,但是希望它能在其他源文件中访问,你应该使用extern关键字,而不是static关键字。

在C++17中,引入了inline变量的概念,并允许对全局变量进行inline修饰。其区别主要体现在以下几个方面:
典型的全局变量在整个程序中只能有一个定义,如果在多个编译单元中定义了相同的全局变量会导致链接错误。

而C++17的inline全局变量,可以在多个编译单元中定义,但所有的定义必须完全相同,编译器会确保它们引用的是同一个对象,不会产生链接错误。

inline全局变量的初始化在程序启动时进行,而且确保只初始化一次,这对于一些需要初始化操作且该操作只能进行一次的情况下很有用。

总的来说,C++17的inline全局变量,能够像inline函数一样,存在于多个编译单元中,且回避了多个编译单元中的全局变量冲突,同时保证了初始化的唯一性。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值