似乎这样会有重复,但也许它很明显它没有被问过......
这是检查C ++类中是否初始化变量(非指针)的正确方法吗?
class MyClass
{
void SomeMethod();
char mCharacter;
double mDecimal;
};
void MyClass::SomeMethod()
{
if ( mCharacter )
{
// do something with mCharacter.
}
if ( ! mDecimal )
{
// define mDecimal.
}
}
答案 0 :(得分:29)
无法检查变量的内容是否未定义。你可以做的最好的事情是分配一个signal / sentinel值(例如在构造函数中),以指示需要进行进一步的初始化。
答案 1 :(得分:21)
未定义的变量将导致编译错误。
您要问的是检查已初始化。但是初始化只是一个值,你应该在构造函数中选择和赋值。
例如:
class MyClass
{
MyClass() : mCharacter('0'), mDecimal(-1.0){};
void SomeMethod();
char mCharacter;
double mDecimal;
};
void MyClass::SomeMethod()
{
if ( mCharacter != '0')
{
// touched after the constructor
// do something with mCharacter.
}
if ( mDecimal != -1.0 )
{
// touched after the constructor
// define mDecimal.
}
}
当然,您应该初始化为逻辑上下文中的某个默认值。
答案 2 :(得分:14)
根据您的应用程序(特别是如果您已经使用了提升),您可能需要查看boost::optional
。
(更新:从C ++ 17开始,可选现在是标准库的一部分,如std::optional
)
它具有您正在寻找的属性,跟踪插槽是否实际包含值。默认情况下,它构造为不保存值并计算为false,但如果计算结果为true,则允许取消引用它并获取包装值。
class MyClass
{
void SomeMethod();
optional<char> mCharacter;
optional<double> mDecimal;
};
void MyClass::SomeMethod()
{
if ( mCharacter )
{
// do something with *mCharacter.
// (note you must use the dereference operator)
}
if ( ! mDecimal )
{
// call mDecimal.reset(expression)
// (this is how you assign an optional)
}
}
更多示例位于the Boost documentation。
答案 3 :(得分:8)
使用C ++ 17 ,您可以使用std::optional
检查变量是否已初始化:
#include <optional>
#include <iostream> // needed only for std::cout
int main() {
std::optional<int> variable;
if (!variable) {
std::cout << "variable is NOT initialized\n";
}
variable = 3;
if (variable) {
std::cout << "variable IS initialized and is set to " << *variable << '\n';
}
return 0;
}
这将产生输出:
variable is NOT initialized
variable IS initialized and is set to 3
要在您提供的代码中使用std::optional
,您必须包含<optional>
标准库标头并将std::optional<...>
添加到相应的变量声明中:
#include <optional>
class MyClass
{
void SomeMethod();
std::optional<char> mCharacter;
std::optional<double> mDecimal;
};
void MyClass::SomeMethod()
{
if ( mCharacter )
{
std::cout << *mCharacter; // do something with mCharacter.
}
if ( ! mDecimal )
{
mDecimal = 3.14159; // define mDecimal.
}
}
答案 4 :(得分:3)
默认情况下,您无法知道变量(或指针)是否已初始化。但是,由于其他人都在告诉你“简单”或“正常”的方法,我会给你一些别的想法。这就是你能够跟踪这样的事情的方式(不,我个人永远不会这样做,但也许你有不同的需求)。
class MyVeryCoolInteger
{
public:
MyVeryCoolInteger() : m_initialized(false) {}
MyVeryCoolInteger& operator=(const int integer)
{
m_initialized = true;
m_int = integer;
return *this;
}
int value()
{
return m_int;
}
bool isInitialized()
{
return m_initialized;
}
private:
int m_int;
bool m_initialized;
};
答案 5 :(得分:3)
使用C ++ - 11,您可以考虑使用智能指针存储变量。考虑这个MVE,toString()
行为取决于bar
被初始化:
#include <memory>
#include <sstream>
class Foo {
private:
std::shared_ptr<int> bar;
public:
Foo() {}
void setBar(int bar) {
this->bar = std::make_shared<int>(bar);
}
std::string toString() const {
std::ostringstream ss;
if (bar) // bar was set
ss << *bar;
else // bar was never set
ss << "unset";
return ss.str();
}
};
使用此代码
Foo f;
std::cout << f.toString() << std::endl;
f.setBar(42);
std::cout << f.toString() << std::endl;
产生输出
unset
42
答案 6 :(得分:2)
没有合理的方法来检查值是否已初始化。
如果您关心某些内容是否已初始化,而不是尝试检查它,请将代码放入构造函数中,以确保它们始终初始化并完成它。
答案 7 :(得分:1)
由于MyClass
是POD类类型,当您创建MyClass
的非静态实例时,那些非静态数据成员将具有不确定的初始值,所以不,这不是一种有效的方式检查它们是否已被初始化为特定的非零值...您基本上假设它们将被零初始化,但事实并非如此,因为您没有在构造函数中对它们进行值初始化。
如果要对类的非静态数据成员进行零初始化,最好创建一个初始化列表和类构造函数。例如:
class MyClass
{
void SomeMethod();
char mCharacter;
double mDecimal;
public:
MyClass();
};
MyClass::MyClass(): mCharacter(0), mDecimal(0) {}
上面构造函数中的初始化列表将数据成员初始化为零。您现在可以正确地假设mCharacter
和mDecimal
的任何非零值必须由您在代码中的其他位置专门设置,并包含可以正确操作的非零值。
答案 8 :(得分:1)
如果您的意思是如何检查成员变量是否已初始化,您可以通过在构造函数中指定它们的sentinel值来完成此操作。选择哨兵值作为在该变量的正常使用中永远不会出现的值。如果变量整个范围被认为是有效的,则可以创建一个布尔值来指示它是否已被初始化。
#include <limits>
class MyClass
{
void SomeMethod();
char mCharacter;
bool isCharacterInitialized;
double mDecimal;
MyClass()
: isCharacterInitialized(false)
, mDecimal( std::numeric_limits<double>::quiet_NaN() )
{}
};
void MyClass::SomeMethod()
{
if ( isCharacterInitialized == false )
{
// do something with mCharacter.
}
if ( mDecimal != mDecimal ) // if true, mDecimal == NaN
{
// define mDecimal.
}
}
答案 9 :(得分:0)
C ++语言中无法检查变量是否已初始化(尽管具有构造函数的类类型将自动初始化)。
相反,您需要做的是提供将类初始化为有效状态的构造函数。静态代码检查器(可能还有一些编译器)可以帮助您在构造函数中找到缺少的变量。这样你就不会让担心处于虚假状态,并且你方法中的if
检查可以完全消失。
答案 10 :(得分:0)
例如,如果您使用字符串而不是字符,则可以执行以下操作:
//a is a string of length 1
string a;
//b is the char in which we'll put the char stored in a
char b;
bool isInitialized(){
if(a.length() != NULL){
b = a[0];
return true;
}else return false;
}
答案 11 :(得分:0)
您可以在断言中引用该变量,然后使用-fsanitize=address
:
void foo (int32_t& i) {
// Assertion will trigger address sanitizer if not initialized:
assert(static_cast<int64_t>(i) != INT64_MAX);
}
这将导致程序使用堆栈跟踪可靠地崩溃(与未定义的行为相反)。
答案 12 :(得分:0)
如果您不喜欢boost和c ++ 17,则可以使用google c ++ lib Abseil来实现。 absl :: optional就像std :: optional一样。
#include <absl/types/optional.h>
class MyClass
{
void SomeMethod();
absl::optional<char> mCharacter;
absl::optional<double> mDecimal;
};
void MyClass::SomeMethod()
{
if (mCharacter)
{
// do something with mCharacter.
}
if (!mDecimal)
{
// define mDecimal.
}
}