我很震惊,这是允许的:
if( int* x = new int( 20 ) )
{
std::cout << *x << "!\n";
// delete x;
}
else
{
std::cout << *x << "!!!\n";
// delete x;
}
// std:cout << *x; // error - x is not defined in this scope
那么,标准是否允许这样做,或者只是编译器扩展?
<子> P.S。由于有几条评论 - 请忽略这个例子是“坏”或危险的。我知道。这只是我想到的第一件事,作为一个例子。
答案 0 :(得分:73)
规范允许这样做,因为C ++ 98。
从第6.4节“选择陈述”:
由条件中的声明引入的名称(由type-specifier-seq或条件的声明符引入)在其声明范围内,直到由条件控制的子语句结束。
以下示例来自同一部分:
if (int x = f()) {
int x; // ill-formed, redeclaration of x
}
else {
int x; // ill-formed, redeclaration of x
}
答案 1 :(得分:18)
它是标准的,即使在旧的C ++ 98版本的语言中:
答案 2 :(得分:16)
不是一个真正的答案(但评论不太适合代码示例),更多的原因是它非常方便:
if (int* x = f()) {
std::cout << *x << "\n";
}
每当API返回“选项”类型(也恰好具有可用的布尔转换)时,可以利用这种类型的构造,以便只能在使用其值合理的上下文中访问该变量。这是一个非常强大的习语。
答案 3 :(得分:7)
while
,if
和switch
语句的条件部分中变量的定义是标准的。相关条款是6.4 [stmt.select]第1段,它定义了条件的语法。
new
失败,则会引发std::bad_alloc
例外。
答案 4 :(得分:2)
以下示例演示了 if 条件中声明的变量的非典型用法。
变量类型为int &
,它既可以转换为布尔值,也可以在然后和 else 分支中使用。
#include <string>
#include <map>
#include <vector>
using namespace std;
vector<string> names {"john", "john", "jack", "john", "jack"};
names.push_back("bill"); // without this push_back, my g++ generated exe fails :-(
map<string, int> ages;
int babies = 0;
for (const auto & name : names) {
if (int & age = ages[name]) {
cout << name << " is already " << age++ << " year-old" << endl;
} else {
cout << name << " was just born as baby #" << ++babies << endl;
++age;
}
}
输出
john was just born as baby #1
john is already 1 year-old
jack was just born as baby #2
john is already 2 year-old
jack is already 1 year-old
bill was just born as baby #3
不幸的是,条件中的变量只能用'='声明语法声明。
这排除了具有显式构造函数的其他可能有用的类型的情况。
例如,下一个使用std::ifstream
的示例将无法编译...
if (std::ifstream is ("c:/tmp/input1.txt")) { // won't compile!
std::cout << "true: " << is.rdbuf();
} else {
is.open("c:/tmp/input2.txt");
std::cout << "false: " << is.rdbuf();
}
2019年1月编辑... 你现在可以效仿我解释不了的事情......
这适用于C ++ 11中的ifstream等可移动类 甚至对于自C ++ 17以来的复制省略以来的非可复制类。
2019年5月编辑:使用auto来缓解冗长
{
if (auto is = std::ifstream ("missing.txt")) { // ok now !
std::cout << "true: " << is.rdbuf();
} else {
is.open("main.cpp");
std::cout << "false: " << is.rdbuf();
}
}
struct NoCpy {
int i;
int j;
NoCpy(int ii = 0, int jj = 0) : i (ii), j (jj) {}
NoCpy(NoCpy&) = delete;
NoCpy(NoCpy&&) = delete;
operator bool() const {return i == j;}
friend std::ostream & operator << (std::ostream & os, const NoCpy & x) {
return os << "(" << x.i << ", " << x.j << ")";
}
};
{
auto x = NoCpy(); // ok compiles
// auto y = x; // does not compile
if (auto nocpy = NoCpy (7, 8)) {
std::cout << "true: " << nocpy << std::endl;
} else {
std::cout << "false: " << nocpy << std::endl;
}
}