在[except.ctor]中,标准(N4140)保证:
...自从输入try块以来构造的所有自动对象都会调用析构函数...
但是在下面的例子中,空输出证明函数的返回值foo没有被破坏,尽管它已被构造.使用g ++(5.2.1)和clang ++(3.6.2-1)以及选项编译-O0 -fno-elide-constructors -std=c++14.
struct A { ~A() { cout << "~A\n"; } };
struct B { ~B() noexcept(false) { throw 0; } };
A foo() {
B b;
return {};
}
int main() {
try { foo(); }
catch (...) { }
}
Run Code Online (Sandbox Code Playgroud)
这是g ++和clang ++中的错误,还是函数返回值不被视为自动对象,还是C++语言中的循环漏洞?
在[stmt.return],[expr.call]或[dcl.fct]中都没有找到一个明确的语句,函数返回值是否被视为自动对象.我找到的最接近的提示是6.3.3 p2:
......退货声明可能涉及临时物体的构造和复制或移动......
和5.2.2 p10:
如果结果类型是左值引用类型或对函数类型的右值引用,则函数调用是左值;如果结果类型是对象类型的右值引用,则为xvalue,否则为prvalue.
我注意到不允许创建零堆长度的非堆分配数组.
// error: cannot allocate an array of constant length zero
char a[0];
Run Code Online (Sandbox Code Playgroud)
我还注意到它允许创建零长度的堆分配数组.
// this is okay though
char *pa = new char[0];
Run Code Online (Sandbox Code Playgroud)
我猜他们都是标准保证(我手头没有标准副本).如果是这样,为什么他们如此不同?为什么不在堆栈上允许零长度数组(反之亦然)?
就个人而言,如果我用gitk查看git或linux repo,我会被大量的合并/分支所震撼.我完全不知道发生了什么.
我假设一般你会尝试在公共回购中拥有尽可能线性的历史记录,并且只有一些分支(例如master,maint,next,pu - that it).即我认为合并很少,并且主要使用rebase.显然我错了.
考虑一个类的两个实现:
struct S1
{
std::vector< T > v;
void push(T && x) { v.push_back(std::move(x)); }
void push(T const & x) { push(T(x)); }
void pop() { v.pop_back(); }
void replace(T && x) { pop(); push(std::move(x)); }
void replace(T const & x) { replace(T(x)); }
};
struct S2
{
std::vector< T > v;
void push(T x) { v.push_back(std::move(x)); }
void pop() { v.pop_back(); }
void replace(T x) { pop(); push(std::move(x)); }
};
Run Code Online (Sandbox Code Playgroud)
S1的push重载表达正是我想要的.S2这push是一种以不那么冗长的方式表达它的方式.
但我担心对象的过度移动构造存在缺陷. …