我的派生类需要提供一个函数,它返回一个std :: vector&给调用者。
我可以声明一个静态成员并在构造函数或CPP文件的“全局作用域”中初始化它。我还可以在派生函数中声明一个局部静态并返回它。
第一个选项在代码的三个不同位置具有声明,初始化和返回功能,而第二个选项在同一位置合并所有三个元素。这些方法之间的对象大小,性能等差异是什么?
编辑通过SergeyA阅读评论后开始。我正在编辑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()
运行之前被初始化。
您可以在生成的程序集中看到初始化保护:
当你这样做的时候
//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
的构造函数)。
这可能是多线程上下文中的一个问题,它可能导致竞争条件,但在这种情况下,您将返回一个静态std::vector
的可变引用,所以我假设线程无论如何对这个特定情况无关紧要。
(nvm。见Nikos对这个问题的回答,为什么这不再是一个问题)
那里有一些误解。如果声明类的静态成员,则无法在构造函数中初始化它。显然,您可以在构造函数中分配它,但只要创建一个新对象(可能多次),它就会被分配,这可能对大多数应用程序没有任何意义。
如果声明一个静态成员,则应该使其成为constexpr并在原位初始化,或者在类定义之外进行初始化。后者让您了解静态初始化顺序惨败的所有荣耀,除非您可以保证成员的编译时初始化。
函数本地静态没有初始化顺序问题,并且具有已定义的顺序。但是,对于函数local static,每次调用函数时,您都需要支付一个小分支(预测)的价格。对于大多数应用程序来说,这甚至都不值得讨论。