返回本地静态的函数和返回静态成员的函数之间有什么区别(对象大小、性能等)?
What are the differences (object size, performance, etc.) between a function that returns a local static and a function that returns a static member?
我的派生类需要提供一个函数,该函数向调用方返回 std::vector&。
我可以声明一个静态成员并在构造函数或 CPP 文件的"全局范围"中初始化它。 我还可以在派生函数中声明一个本地静态并返回它。
第一个选项在代码的三个独立位置具有声明、初始化和返回功能,而第二个选项将所有三个元素合并到同一位置。 这些方法之间的对象大小、性能等有何区别?
通过谢尔盖阅读评论后,编辑从这里开始。 我正在编辑 PeterT 的代码示例,添加一个示例以显示构造函数利用push_back。 所以我必须向 SergeyA 承认初始化确实发生在全局范围内,如下所述,变量s_val出现在四个单独的位置。
//ex.h
#include <vector>
using intVec = std::vector<int>;
struct ex
{
ex();
static intVec s_val;
intVec& getVal();
};
//ex.cpp
intVec ex::s_val = intVec(5);
ex::ex()
{
if (s_val.size() == 0) {
s_val.reserve(5);
s_val.push_back(1);
s_val.push_back(4);
s_val.push_back(0);
s_val.push_back(2);
s_val.push_back(3);
}
assert(s_val.size() == 5);
}
intVec& ex::getVal()
{
return s_val;
}
我想现代化和简化代码以使用初始值设定项列表。 听起来返回全局静态允许我以干净有效的方式做到这一点。 这是对的吗?
//ex.h
#include <vector>
using intVec = std::vector<int>;
struct ex
{
intVec& getVal();
};
//ex.cpp
static intVec s_val = { 1, 4, 0, 2, 3 };
intVec& ex::getVal()
{
assert(s_val.size() == 5);
return s_val;
}
本地静态将在每次调用函数时产生初始化保护(互斥锁)的成本。这是由于 C++11 保证了静态的线程安全初始化,对于本地静态意味着访问序列化。
全局静态(还包括静态类成员)不会产生该开销,因为全局静态是在运行main()
之前初始化的。
您可以在生成的程序集中看到初始化保护:
https://godbolt.org/z/BzdzvN
当你这样做时
//ex.h
#include <vector>
using intVec = std::vector<int>;
struct ex
{
static intVec s_val;
intVec& getVal();
};
//ex.cpp
intVec ex::s_val = intVec(5);
intVec& ex::getVal()
{
return s_val;
}
然后,用于实例化向量的初始化代码发生在main()
但如果你这样做
//ex.h
#include <vector>
using intVec = std::vector<int>;
struct ex
{
intVec& getVal();
};
//ex.cpp
intVec& ex::getVal()
{
static intVec s_val = intVec(5);
return s_val;
}
然后,静态变量(被调用std::vector
的构造函数)的初始化在第一次调用函数时发生。
这在多线程上下文中可能是一个问题,它可能导致竞争条件,但在这种情况下,您将返回对静态(参见 Nikos 对这个问题的回答,了解为什么这不再是一个问题)std::vector
的可变引用,因此我假设线程对于这种特定情况无关紧要。
那里有一些误解。如果声明类的静态成员,则无法在构造函数中初始化它。您显然可以在构造函数中分配它,但是每当创建新对象(可能多次)时都会分配它,这对于大多数应用程序可能没有任何意义。
如果声明静态成员,则应将其设为 constexpr 并就地初始化,或者在类定义之外初始化。后者使您暴露在静态初始化顺序惨败的所有荣耀中,除非您可以保证成员的编译时初始化。
函数本地静态没有初始化顺序问题,并且具有定义的顺序。但是,使用函数本地静态,每次调用函数时,您都会支付一个分支(预测)的微不足道的代价。对于大多数应用程序,这甚至不值得谈论。
- 为什么将值返回函数传递给重载=运算符对运算符函数有效,而对其他运算符无效
- 编译器警告:执行到达值返回函数的末尾而不返回值
- 接收和返回函数指针的函数指针的类型?
- 我的动态链接队列在同一输出流中调用时不正确地输出三个返回函数
- C++函数链返回函数
- 返回函数指针的函数的签名
- 由于值返回函数中的错误,程序无法编译.它说未声明的标识符
- 非常量引用返回函数在常量值返回函数上用作 r 值
- 如何在 C++ 中从 void 返回函数访问变量
- 返回函数中带有 2 个可选 ctor 的对象
- 如何在 c++ 中返回函数的结构向量
- 返回 C++ 函数中的引用
- 使用向量时,当返回函数更改时,无法看到输出
- 如何在递归中使用返回函数
- 返回函数模板的类型C++作为第二个模板参数
- 为什么静态指针返回函数中有一个"静态"键?
- 递归返回函数,在特殊情况下不返回
- 从类返回函数
- 从类成员函数返回函数指针
- 从返回函数中推断不存在的模板参数