下面是一个代码片段,可以在vs2015中编译和运行而不会出错
#include<iostream>
using namespace std;
class A {
public:
A(int b) :k(b) {}//second time
const int k = 666;//first time
};
int main() {
A a(555);
cout << a.k << endl;
return 0;
}
Run Code Online (Sandbox Code Playgroud)
输出是555
.但据我所知,const
对象应该只初始化一次,之后值不可修改.
先来看看什么C++入门谈到unique_ptr
和shared_ptr
:
$ 16.1.6.效率和灵活性
我们可以确定
shared_ptr
不将删除器作为直接成员,因为删除器的类型直到运行时才知道.因为删除器的类型是a
unique_ptr
类型的一部分,所以删除器成员的类型在编译时是已知的.删除器可以直接存储在每个unique_ptr
对象中.
所以似乎shared_ptr
没有直接的删除成员,但unique_ptr
确实如此.然而,另一个问题的最高投票回答说:
如果将deleter作为模板参数提供(如
unique_ptr
),则它是类型的一部分,您不需要在此类型的对象中存储任何其他内容.如果将deleteter作为构造函数的参数传递(如shared_ptr
),则需要将其存储在对象中.这是额外灵活性的代价,因为您可以为相同类型的对象使用不同的删除器.
引用的两段完全相互矛盾,让我感到困惑.更重要的是,许多人说unique_ptr
是零开销,因为它不需要将删除器存储为成员.但是,正如我们所知,unique_ptr
有一个构造函数unique_ptr<obj,del> p(new obj,fcn)
,这意味着我们可以将删除函数传递给它,因此unique_ptr
似乎已将删除函数存储为成员.真是一团糟!
例如:
#include<iostream>
using namespace std;
int main() {
int i = i=0; //no warning
cout << i << endl;
return 0;
}
Run Code Online (Sandbox Code Playgroud)
在vs2015中编译,没有警告和输出0
.这个代码片段是否定义明确,虽然看起来有点奇怪?
但是,在这个在线编译器(g++ prog.cc -Wall -Wextra -std=c++17
)中它会抛出一个警告:
prog.cc: In function '`int main()`':
prog.cc:8:12: warning: operation on '`i`' may be undefined [-Wsequence-point]
`int i=i=0;`
Run Code Online (Sandbox Code Playgroud) 例如,在一个源文件中:
extern int a[10];
int main()
{
(void)sizeof(a);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
在第二个源文件中,我们有:
int a[20];//different with the first source
Run Code Online (Sandbox Code Playgroud)
上面的代码是否会导致未定义的行为?据我所知,在C中它说:
引用同一对象或函数的所有声明都应具有兼容类型; 否则,行为未定义.
是int[10]
和int[20]
兼容(在c
视图中)?那么C++标准呢?
此外,如果没有第二个源文件,使用是否合法sizeof(a)
(a
只有声明)?
例:
class A
{
class B
{
A c;//error!A is an incomplete type
void test() { A b;/*OK,but why?*/ }
};
};
Run Code Online (Sandbox Code Playgroud)
代码片段对我来说似乎很奇怪,这两种用法有A
什么区别?
以下是代码段:
#include <iostream>
using namespace std;
struct B{
int b;
~B(){cout <<"destruct B" << endl;}
};
B func(){
B b;
b.b = 1;
return b;
}
int main(){
const B& instance = (const B&)func(); //is `instance` a dangling reference?
cout <<instance.b<<endl;
return 0;
}
Run Code Online (Sandbox Code Playgroud)
在这个在线编译器中的输出是
destruct B
destruct B
1
Run Code Online (Sandbox Code Playgroud)
因此返回值似乎比cout
操作早破坏.所以这instance
似乎是一个悬垂的参考.
如果我们const B& instance = (const B&)func();
改为 const B& instance =func();
,那么结果是
destruct B
1
destruct B
Run Code Online (Sandbox Code Playgroud)
作为补充,如果我在vs2015中测试代码,那么输出是最后一个.但是,如果在gcc(4.6之前)中进行测试,则输出为前者,但后者为4.6之后的版本.所以我想知道在线编译器是错误的还是引用实际上是悬空的.
引自C++ Primer $ 12.1.6:
A
weak_ptr
(表12.5)是一个智能指针,它不控制它指向的对象的生命周期.相反,weak_ptr指向由a管理的对象shared_ptr
.将weak_ptr绑定到shared_ptr 不会更改其引用计数shared_ptr
.一旦shared_ptr
指向对象的最后一个消失,对象本身将被删除.即使有weak_ptrs
指向它的名称weak_ptr
,该对象也将被删除 -因为该名称捕获了一个weak_ptr
"虚弱地"共享其对象的想法.
但是,我读过一篇文章说:
使用make_shared更有效率.shared_ptr实现必须将管理信息保存在由引用给定对象的所有shared_ptrs和weak_ptrs共享的控制块中.特别是,该管家信息不仅包括一个而且包括两个参考计数:
"强引用"计数用于跟踪当前使对象保持活动状态的shared_ptrs的数量.当最后一个强引用消失时,共享对象被销毁(并可能被解除分配).
"弱引用"计数用于跟踪当前正在观察对象的weak_ptrs的数量.当最后一个弱引用消失时,共享内务控制块被销毁并解除分配(如果共享对象尚未释放,则将其解除分配).
据我所知,shared_ptr
创建的make_shared
是与那些引用计数在同一个控制块中weak_ptr
.所以在最后一个到期之前对象不会被释放.
weak_ptr
实际上会影响该对象的生命周期. shared_ptr
需要跟踪它的弱引用?weak_ptr可以通过检查控制块中的强引用来判断对象是否存在,所以我认为控制块不需要跟踪弱引用. 只是出于好奇,控件块的shared_ptr
外观是什么样的?它是这样的:
template<typename T>
class control_block
{
T object;
size_t strong_refs;
size_t weak_refs;
void incre();
void decre();
//other member functions...
};
//And in shared_ptr:
template<typename T>
class …
Run Code Online (Sandbox Code Playgroud)例如,HotSpot JVM 通过捕获 SIGSEGV 信号来实现空指针检测。NullPointerException
那么,如果我们从外部手动生成 SIGSEGV,在某些情况下也会被识别吗?
在cppref中,它给出了常量初始化的语法:
static T & ref = constexpr;
static T object = constexpr;
Run Code Online (Sandbox Code Playgroud)
这是我的两个问题:
一个左值引用怎么可能T &
没有const
绑定到a constexptr
,它是常量且不可修改的?
我试着提供一些例子,但失败了:
static int& ref = 6; //error, need a `const`
constexpr int a = 6; static int& ref = a; //error, need a `const`
Run Code Online (Sandbox Code Playgroud)
对于持续初始化的对象是否必须是const
/ static
?在标准中它说:
执行恒定初始化如果与静态或线程存储持续时间的变量或临时对象由恒定初始化为实体初始化.
这里标准没有将obj指定为const-qualified
/ static-qualified
.
从cppref所说的值初始化
如果T是没有默认构造函数的类类型,或者是用户提供或删除的默认构造函数,则该对象是默认初始化的 ;
但由于该类类型已删除默认构造函数,该对象如何进行默认初始化?
据我所知,类类型的默认初始化需要访问默认构造函数.如果我们有:
struct A {
A() = delete;
int k;
};
Run Code Online (Sandbox Code Playgroud)
然后A *a = new A;
会失败,也会失败A* a = new A();
.
但是A a{};
没关系.但为什么?根据cppreference
否则,如果braced-init-list为空且T是具有默认构造函数的类类型,则执行值初始化.
c++ ×9
c++11 ×5
c ×1
const ×1
constexpr ×1
java ×1
jvm ×1
jvm-hotspot ×1
linux ×1
shared-ptr ×1
unique-ptr ×1