作者回复: 谢谢。这个专栏是要求之前学过、用过C++的。没学过的不合适。
作者回复: 其他都对,不过,自定义delete似乎目前没这个必要?
1. 好问题。静态存储区既不是堆也不是栈,而是……静态的。意思是,它们是在程序编译、链接时完全确定下来的,具有固定的存储位置(暂不考虑某些系统的地址扰乱机制)。堆和栈上的变量则都是动态的,地址无法确定。
2. thread_local和静态存储区类似,只不过不是整个程序统一一块,而是每个线程单独一块。用法上还是当成全局/静态变量来用,但不共享也就不需要同步了。
3. 非静态数据成员加上动态类型所需的空间。注意后者不一定是4,而一般是指针的大小,在64位系统上是8字节。还有,要考虑字节对齐的影响。静态数据成员和成员函数都不占个别对象的空间。
作者回复: 认真记笔记非常好。
不过,建议笔记还是记关键字和要点,解释文字不用多。否则篇幅跟原文接近就意义不大了。
作者回复: 凡生命周期超出当前函数的,一般需要用堆(或者使用对象移动传递)。反之,生命周期在当前函数内的,就该用栈。
作者回复: 如果这个变量下面还有用到的地方,这是个好习惯。不过,这个习惯主要还是从C来的。现代C++不推荐一般代码里再使用裸指针和new/delete的。
作者回复: 这里主要牵涉到“栈帧”是如何定义的。虽然“参数属于调用者而非被调用者,一般也是由调用者来释放”概念上没有错,但我当时对“栈帧”的定义想当然了。我后来又查了一下定义(用词要以大家接受的用法为准),发现参数和局部变量应该算作一个栈帧里。也就是说,你们这儿的质疑是有道理的。所以,目前我已经把图修改了,这样应该就都没有疑问了。
作者回复: 如果刚开始学的话,这个专栏可能会有点挑战。可以先看一下 C++ 之父的 A Tour of C++,国内出版叫《C++语言导学》(谢谢小猪钱钱同学告知)。
另外,《C++ Primer》名声很响,但 848 页初学有点厚了。注意不是《C++ Primer Plus》,这本跟前者完全无关,不推荐。
作者回复: 嗯,有点道理。但需要学习能力很强,因为我假设你是懂C++的基本语法的。
作者回复: 「std::terminate() 为 C++ 运行时在异常处理因下列原因失败时调用:
1) 抛出的异常未被捕捉(此情况下是否进行任何栈回溯是实现定义的)
…」
https://zh.cppreference.com/w/cpp/error/terminate
作者回复: 哈,你是第一个用这个形容词的。😁
作者回复: 这就是面向对象里的基本用法了。在面向对象的继承体系了,shape需要有一个虚析构函数。这样如果有一个shape*实际指向circle,在delete这个指针时,调用的是circle的析构函数(当然析构过程中,最后也会再调用shape的析构函数)。
下面的代码可以展示这个过程:
#include <stdio.h>
class shape {
public:
virtual ~shape()
{
puts("~shape");
}
};
class circle : public shape {
public:
~circle()
{
puts("~circle");
}
};
int main()
{
shape* ptr = new circle();
delete ptr;
}
结果是:
~circle
~shape
作者回复: Meyers的书对提升C++能力到下一个台阶是非常重要的。我也从中学了很多。
作者回复: 一般不这么看。异常安全性对系统有很多约定,违反了约定,通常 terminate 会被调用。这种情况下就是不做清理工作的。
在Windows上,你甚至可以用 catch(...) 捕获指针越界访问(需要 /EHa 编译参数),但前提条件一样是你需要去 catch。
从另一个角度,程序崩溃时,大部分资源都会被操作系统回收,不会对系统造成问题。我们说泄漏,关注的主要是程序(长时间)运行过程中应该释放而没有释放掉的东西,如内存、文件句柄、锁等等。
作者回复: 因你这句话,我特地又去查了一下,目前看到的图,开口永远是上方。中英文资料都是如此。
这个词的来源实际上可能是堆盘子。显然,你只能从上面取放盘子……
作者回复: Go也有它的优点。写网络应用Go还是不错的。好的语言多了,也是C++用得少了些的原因。
作者回复: 1. 恰恰相反,大部分语言里都有像指针的东西,只是不叫指针,不能随意转换和做加减法,也就不那么危险。很多语言都没有值语义——传递对象,而不是对象的指针/引用。
2. 得到一个指针,当然是引用语义。
3. 不是完整表达式,问题没有意义。
作者回复: 这么说吧,Java里的一个对象变量相当于C++的指针变量,. 相当于 C++ 的 ->。其他就再多读两遍体会一下吧。
作者回复: 智能指针也可以不是引用计数的。🤓
不过不管那种,下一讲都会讨论。
作者回复: 常用语言里只有C++区分这两种标记(就是文中的例子)。你不能写ptr.call()。一般其他语言里都这样写。