返回本地静态函数的函数与返回静态成员的函数之间有什么区别(对象大小,性能等)?

时间:2019-04-10 18:44:46

标签: c++ static

我的派生类需要提供一个将std :: vector&返回给调用者的函数。

我可以声明一个静态成员,然后在CPP文件的构造函数或“全局范围”中对其进行初始化。我还可以在派生函数中声明一个局部静态变量并返回它。

第一个选项在代码的三个单独位置具有声明,初始化和返回功能,而第二个选项将所有三个元素合并在同一位置。这些方法之间的对象大小,性能等有什么区别?

通过SergeyA阅读评论后,编辑将从此处开始。我正在编辑PeterT的代码示例,添加了一个示例以显示构造函数使用push_back。因此,我必须向SergeyA承认,初始化确实发生在全局范围内,并且如下所述,在变量s_val出现的位置有四个单独的位置。

String username = usernameTxt.getText();  
    String password = passwordTxt.getText();


     if  ("".equals(username))
  {
        JOptionPane.showMessageDialog(null,"Please Enter Your Username.");
    }
      else  if ("".equals(password))
  {
        JOptionPane.showMessageDialog(null,"Please Enter Your Password.");
    }

    else {
        File file = new File("ResidentLoginCredentials.txt");

        try {
            FileReader fr = new FileReader(file);
            BufferedReader br = new BufferedReader(fr);
            String data;
            residentlogincredentials res;

            while ((data = br.readLine()) != null) {
                res = new residentlogincredentials(data);
                if (usernameTxt.equals(username)) && (passwordTxt.equals(password)) {
                   JOptionPane.showMessageDialog(null,"Welcome Back, Resident.","Success",JOptionPane.INFORMATION_MESSAGE);
                   passwordTxt.setText(null);
                   usernameTxt.setText(null);
                   residentdashboard rd = new residentdashboard();
                   rd.setVisible(true);
                   this.setVisible(false); 
                }
            }

        } catch (FileNotFoundException ex) {

        } catch (IOException ex) {
            JOptionPane.showMessageDialog(this, "Invalid Username.");

        }
    }

我想对代码进行现代化和简化,以使用初始化列表。听起来像返回全局静态变量使我能够以一种干净高效的方式进行操作。这是正确的吗?

//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;
}

3 个答案:

答案 0 :(得分:1)

在每次调用该函数时,局部静态变量将导致初始化保护(互斥锁)的开销。这是由于C ++ 11保证了线程安全的静态初始化,对于本地静态而言,这意味着访问序列化。

全局静态变量(也包括静态类成员)不会产生该费用,因为全局静态变量是在main()运行之前初始化的。

您可以在生成的程序集中看到初始化防护:

https://godbolt.org/z/BzdzvN

答案 1 :(得分:0)

执行此操作

//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的答案)

答案 2 :(得分:0)

那里有些误会。如果声明该类的静态成员,则无法在构造函数中对其进行初始化。您显然可以在构造函数中分配它,但是只要创建一个新对象(可能多次),就会分配它,这对于大多数应用程序可能毫无意义。

如果声明静态成员,则应使其成为constexpr并就地初始化,或者在类定义之外进行初始化。后者使您暴露于静态初始化顺序惨败的所有荣耀,除非您可以保证为成员进行编译时初始化。

局部函数静态没有初始化顺序问题,并且具有已定义的顺序。但是,使用局部静态函数时,每次调用该函数时,您需要支付分支的小巧价格(预测的)。对于大多数应用程序,这甚至不值得讨论。