【问题标题】:Is it better to use `static const std::string` or just `const std::string` in a method/function?在方法/函数中使用 `static const std::string` 还是仅使用 `const std::string` 更好?
【发布时间】:2014-01-24 10:16:38
【问题描述】:

我有一个方法/函数:

void foo() {

  static const std::string strSQLQuery = "SELECT ... ";
  // or maybe
  const std::string strSQLQuery = "SELECT ... "; 

  // some operations on strSQLQuery
  // i.e. concatenating with WHERE, etc.:
  const std::string strSQL = strSQLQuery + strWHERE;

  doSthOnDataBase(strSQL);
}

(SQL只是一个例子)

  1. static const 只会被初始化一次,但会一直保存在内存中,直到进程结束。
  2. const 将在每次运行 foo() 时被初始化,但在 {} 块结束时释放内存(堆栈)。

另一方面,字符串"SELECT ... " 仍然必须在程序代码中进行硬编码。无论我们使用 1. 还是 2.

那么哪种方法更好呢?使用static const std::string 还是仅使用const std::string

或者也许没有人回答,因为这取决于我想如何使用foo()——每秒调用 1000 次(然后我不想每次都初始化一个变量)或每月调用 1000 次(那我不在乎)。

(我已阅读问题Difference between static const char* and const char* 并特别回答https://stackoverflow.com/a/2931146/945183,但它们适用于const char*。)

【问题讨论】:

  • 您似乎已经概述了每种解决方案的优缺点。提示:没有绝对更好的选择。
  • 请注意,当您有这样的static 时,您的程序会锁定。
  • 我会选择静态常量,因为它需要更少的内存(堆栈是一种非常昂贵的浪费)并且它基本上具有相同的效果。附带说明一下,在通常将其全局定义为结构成员的方法中定义 const 是非常罕见的......
  • @Pandrei: wat。静态字符串意味着如果在多线程上下文中使用您的代码将会爆炸。非静态线程意味着几个字节放在堆栈上,其余的放在堆上。我不知道你在说什么。 “堆栈内存浪费很昂贵”。
  • 您可以使用const char* const strSQLQuery = "SELECT ... "

标签: c++ string static


【解决方案1】:

分析它。很有可能,数据库之旅完全使字符串的初始化成本相形见绌。

正如已经指出的,局部静态变量在所有编译器上都不是线程安全的。它们在 GCC 中,C++11 要求它们,但微软直到 VS2013 才真正实现这一点。

【讨论】:

  • MS 直到 VS2013 才正确实现了一些 C++11。他们还没有完全到那里......
  • 我知道,weTeim 的答案与此类似,但 Sebastian ,,更切中要害,恕我直言,并且没有重复我在问题中包含的想法。
【解决方案2】:

如果是成员变量,static const is safe,只要您不故意通过强制转换来击败 const 部分。但是从您链接的 cmets 中,局部变量是不同的:

局部静态变量在第一次遇到它的定义时被初始化,但在函数退出时不会被破坏。所以它在函数的调用之间保持它的值。

为了确保安全,gcc 会发出锁定以保护初始化,但 MS C++ 不会像 here 所述那样,因此这可能是安全的,也可能不是安全的,这取决于编译器,即使假定安全也会产生有害的副作用。

这里的权衡似乎是效率与可维护性。额外的小速度是否值得引入一些微妙的错误。在研究这一点时,我现在对我的观点进行了完整的讨论,我通常会说不。特别是因为在这种情况下,它是一个简单的字符串初始化,然后是一个冗长的数据库调用。

【讨论】:

    【解决方案3】:

    据我所知,在您的情况下不需要“静态”。 1) 当您声明和定义一个 const 变量时,编译器有机会将所有出现的值替换为您分配的值,如下所示:

    const int var = 9;
    int b = sqrt( var );
    

    会变成

    int b = sqrt( 9 );
    

    这和 C 风格的#define 一样。如果这是您想要的,那么您已经拥有它而没有“静态”。

    2) 正如其他人所说,静态变量即使在 foo() 返回后仍然存在。我想这不是你的目标

    【讨论】:

    • std::string 是动态初始化和用户定义的。祝你好运找到一个编译器对其进行持续传播。
    【解决方案4】:

    静态非原始局部变量(const 与否)在每个函数调用(初始化标志)上进行原子读取。只有在通过编译器标志特别请求时,它们才是线程安全的(说到 GCC)。在运行时构造的字符串strSQL 对性能的影响(因为堆分配)比静态初始化导致的原子读取要大得多。

    最快的应该是这样的:

    void call(std::string const& where) {
        static char prefix[] = "SELECT ...";
    
        std::string strSQL;
        strSQL.reserve(sizeof(prefix)/sizeof(char) + strWHERE.size()); 
        strSQL.append(prefix, sizeof(prefix)/sizeof(char)).append(strWHERE);
        ...
    }
    

    您是否需要为了速度而牺牲可读性是另一个问题。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2011-01-07
      • 2016-08-28
      • 2020-06-26
      • 1970-01-01
      • 1970-01-01
      • 2016-06-25
      • 1970-01-01
      相关资源
      最近更新 更多