C++构造函数:在初始化器列表之前初始化局部变量
C++ constructor: Initialize local variable before initializer list
如何在构造函数(堆栈上)中存储初始值设定项列表所需的临时状态?
例如,实现这个构造函数…
// configabstraction.h
#include <istream>
class ConfigAbstraction
{
public:
ConfigAbstraction(std::istream& input);
private:
int m_x;
int m_y;
int m_z;
};
…使用这样的有状态助手类?
// mysillyparserdontworry.h
#include <json/reader.h> //jsoncpp
class MySillyParserDontWorry
{
public:
MySillyParserDontWorry(std::istream& input) { input >> m_parseTree; }
int intByName(const char* name) const { return m_parseTree[name].asInt(); }
private:
Json::Value m_parseTree;
};
我的尝试:
// configabstraction.cpp
ConfigAbstraction::ConfigAbstraction(std::istream& input)
: local_parserState(input) // init local variable first: Not possible!
, m_a(local_parserState.intByName("a"))
, m_b(local_parserState.intByName("b"))
, m_c(local_parserState.intByName("c"))
{
MySillyParserDontWorry local_parserState; // ...because it is local
}
使用C++11,您可以通过委派构造函数来解决此问题:
class ConfigAbstraction
{
public:
ConfigAbstraction(std::istream& input);
private:
ConfigAbstraction(const MySillyParserDontWorry& parser);
int m_a;
int m_b;
int m_c;
};
ConfigAbstraction::ConfigAbstraction(const MySillyParserDontWorry& parser)
: m_a{parser.intByName("a")}
, m_b{parser.intByName("b")}
, m_c{parser.intByName("c")}
{
}
ConfigAbstraction::ConfigAbstraction(std::istream& input)
: ConfigAbstraction{MySillyParserDontWorry{input}}
{
}
问题的另一种解决方案是将三个单独的int
打包到一个公共数据结构中。这将允许您使用私有静态辅助函数初始化该类型的对象。能够初始化对象而不是稍后分配给它也允许它为const
(如果需要的话)。
以下是std::tuple
的一个示例。但您也可以创建自己的助手struct
,甚至std::array<int, 3>
;基本思想保持不变:有一个成员对象,而不是三个
#include <istream>
#include <tuple>
class MySillyParserDontWorry
{
public:
MySillyParserDontWorry(std::istream& input) { /* ... */ }
int intByName(const char* name) const { return /* ... */ 0; }
};
class ConfigAbstraction
{
public:
ConfigAbstraction(std::istream& input);
private:
static std::tuple<int, int, int> parse(std::istream& input)
{
std::tuple<int, int, int> result;
MySillyParserDontWorry parser(input);
std::get<0>(result) = parser.intByName("a");
std::get<1>(result) = parser.intByName("b");
std::get<2>(result) = parser.intByName("c");
return result;
}
std::tuple<int, int, int> const m;
};
ConfigAbstraction::ConfigAbstraction(std::istream& input)
: m(parse(input))
{
}
为什么不简单地在构造函数的主体中进行赋值呢?
ConfigAbstraction::ConfigAbstraction(std::istream& input)
: m_a(0)
, m_b(0)
, m_c(0)
{
MySillyParserDontWorry local_parserState;
m_a = local_parserState.intByName("a");
m_b = local_parserState.intByName("b");
m_c = local_parserState.intByName("c");
}
有什么具体的要求阻碍你这么做吗?
C++的人为限制
这不是一个人为的限制。局部变量的初始化应该如何在其函数范围之外进行?这只会导致一个巨大的混乱,变量实际上是初始化的(命名冲突除外)。
不能在成员之前初始化局部变量。原因很简单(所以这不是人为的限制):
必须在构造函数主体开始之前对成员进行初始化(构造),因为构造函数主体可能会访问它们,并且需要为此访问对它们进行初始化。另一方面,在代码进入构造函数主体之前,局部变量并不存在(对于任何其他函数)。结论-在成员之前初始化局部变量是不可能的。
相关文章:
- 未初始化的变量有什么危险
- 使用的未初始化局部变量'Quick'
- C++如何通过"constructor initialization"初始化行变量?
- "local scope"中的 C++ 初始化静态变量
- 为什么我的 c++ 程序检查不是初始化的变量?
- 使用大括号或括号初始化成员变量
- 使用 std::ios_base::Init 正确初始化全局变量
- 'auto *x = new some_struct{};"是一个未初始化的变量?
- 是否可以将已经初始化的变量转换为 void*?
- Clang++ 6.0 内存清理器未报告返回值指示条件分支的函数中的未初始化局部变量
- 为什么默认情况下初始化局部变量
- 如果仅在 lambda 中使用,则不会在发布版本中初始化局部静态变量
- 对初始化时使用的未初始化局部变量感到困惑
- 如何在Qt(gcc 64位)中禁用自动初始化局部变量
- 在函数中初始化局部变量时出现问题
- 为什么VS编译器不会在C++上自动初始化局部变量?
- C++构造函数:在初始化器列表之前初始化局部变量
- 如何初始化局部联合变量
- 实际初始化的未初始化局部变量
- 收到未初始化局部变量的警告