C++ 11标准的第8.5p7段规定:
对值类型T的对象进行值初始化意味着:
如果T是具有用户提供的构造函数(12.1)的(可能是cv限定的)类类型(第9节),则调用T的默认构造函数(如果T没有可访问的默认构造函数,则初始化是错误的) ;
如果T是一个(可能是cv限定的)非联合类类型而没有用户提供的构造函数,那么该对象是零初始化的,如果T的隐式声明的默认构造函数是非平凡的,则调用该构造函数.
如果T是数组类型,那么每个元素都是值初始化的;
否则,该对象被零初始化.
我有一个问题,理解上面的粗体字符.附加调用T的隐式默认构造函数如何改变零初始化,这种情况刚刚发生?
据铛,gcc和vs2013,功能Outer::f是不是类的朋友Outer::Inner.
struct Outer {
void f() {}
class Inner {
friend void f();
static const int i = 0;
};
};
void f() { int i = Outer::Inner::i; }
Run Code Online (Sandbox Code Playgroud)
从[namespace.memdef]/3我希望函数Outer::f成为朋友Outer::Inner,而不是::f因为友元声明不是包含名称的名称空间中的第一个f.
[namespace,memdef]/3(重点是我的):
首先在名称空间中声明的每个名称都是该名称空间的成员.如果非本地类中的朋友声明首先 声明了类,函数,类模板或函数模板97,则该朋友是最内部封闭命名空间的成员.友元声明本身不会使名称对非限定查找(3.4.1)或限定查找(3.4.3)可见.[注意:如果在命名空间范围内提供匹配的声明(在类定义授予友谊之前或之后),则朋友的名称将在其命名空间中可见. - 结束注释]如果调用了友元函数或函数模板,则可以通过名称查找找到其名称,该名称查找考虑名称空间中的函数和与函数参数类型相关联的类(3.4.2).如果友元声明中的名称既不是限定语句也不是模板标识,并且声明是函数或详细类型说明符,则确定实体是否先前已声明的查找不应考虑最内层封闭命名空间之外的任何范围.
例如,字符串文字"Hello"的类型是什么,const char[6]或者const char*?
请考虑以下代码.g ++和clang ++都抱怨(正确地)构造函数A(int)在类中是私有的D.注意,作为A一个虚拟的基类的D,A具有在被初始化MEM-初始化类的D,最派生类,根据在C++ 11§12.6.2/ 7.查看实例.
class A {
public:
A(int i) : x(i) { }
A() : x(1) {}
int x;
};
class B : private virtual A {
protected:
B(int i) : A(i) { } };
class C : public B, private virtual A {
protected:
C(int i) : A(i), B(i) { }
};
class D : public C {
public:
D() : …Run Code Online (Sandbox Code Playgroud) 从[class.access]/7我们得到以下句子:
类似地,
A::B作为基本说明符的使用是良好形成的,因为它D是派生自的A,因此必须推迟对基本说明符 s的检查,直到看到整个基本说明符列表.
class A {
protected:
struct B { };
};
struct D: A::B, A { };
Run Code Online (Sandbox Code Playgroud)
查看clang的实例.事实上,clang还抱怨这个片段,不需要延期.
class A {
protected:
struct B { };
};
struct D: A, A::B { };
Run Code Online (Sandbox Code Playgroud)
为什么这段代码不能编译?
PS:gcc和VS21013也不编译代码.
请注意,[class.mem] p6中未提及trailing-return-type
一个完整的类的上下文是一个
(6.1)函数体,
(6.2)默认参数,
(6.3)noexcept-specifier([except.spec]),
(6.4)合同条件,或
(6.5)默认成员初始化程序在类的成员规范内.[注意:如果嵌套类在封闭类的成员规范中定义,则嵌套类的完整类上下文也是任何封闭类的完整类上下文. - 结束说明]
[expr.prim.this] p2也有关于此的说明:
如果声明声明了类X的成员函数或成员函数模板,则表达式是可选的cv-qualifier-seq和函数定义结尾之间的类型为"指向cv-qualifier-seq X的指针"的prvalue ,成员声明者或声明者.它不应出现在可选的cv-qualifier-seq之前,它不应出现在静态成员函数的声明中(尽管它的类型和值类别是在静态成员函数中定义的,因为它们在非静态成员函数中) .[注意:这是因为声明匹配在完整声明符已知之前不会发生.- 尾注] [注意:在trailing-return-type中,为了类成员访问的目的,要求定义的类不需要完整.稍后声明的类成员不可见.[例子:......
此代码int在构造Dog类中的对象时抛出异常UseResources.该int异常由正常捕获try-catch块和代码输出:
Cat()
Dog()
~Cat()
Inside handler
Run Code Online (Sandbox Code Playgroud)
#include <iostream>
using namespace std;
class Cat
{
public:
Cat() { cout << "Cat()" << endl; }
~Cat() { cout << "~Cat()" << endl; }
};
class Dog
{
public:
Dog() { cout << "Dog()" << endl; throw 1; }
~Dog() { cout << "~Dog()" << endl; }
};
class UseResources
{
class Cat cat;
class Dog dog;
public:
UseResources() : …Run Code Online (Sandbox Code Playgroud) 这是Stroustup的书第3版,第362页的摘录:
原则上,抛出异常时会复制异常,因此处理程序会获取原始异常的副本.实际上,异常可能会在被捕获之前被复制多次.因此,我们不能抛出无法复制的异常.实施可以应用各种用于存储和传输异常的策略.但是,保证有足够的内存允许new抛出标准的outofmemory异常bad_alloc.
为什么下面max(x, y)表达式return max(max(x, y), z);中调用的重载解析导致调用非模板函数char const* max(char const*, char const*)?
至于我能理解,该函数max<const char*>(x, y)是一个比以前更好的贴合,因为x是const char* const&和y是const char* const&!
#include <iostream>
template <typename T>
T const& max (T const& x, T const& y)
{
return x < y ? y : x;
}
char const* max (char const* x, char const* y)
{
return std::strcmp(x, y) < 0 ? y : x;
}
template <typename T> …Run Code Online (Sandbox Code Playgroud) 此代码无法在VS2010中编译.它会发出错误C2440:'argument':无法从'A'转换为'A&',但根据标准中的12.8p2,它A::A(A&)是一个有效的复制构造函数,并且a是表达式A b = foo(a);中的左值main().
#include <iostream>
class A
{
public:
int x;
A(int a) { x = a; std::cout << "Constructor\n"; }
A(A& other) { x = other.x; std::cout << "Copy ctor\n"; }
A(A&& other) { x = other.x; other.x = 0; std::cout << "Move ctor\n"; }
};
A foo(A a)
{
return a;
}
int main(void)
{
A a(5);
A b = foo(a);
}
Run Code Online (Sandbox Code Playgroud)