c++虚继承

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
#include <iostream>
 
using namespace std;
 
class Base {
public:
	virtual ~Base() {}
	virtual void func() = 0;
	int base_;
};
 
class SubLeft : virtual public Base {
public:
	int subLeft_;
};
 
class SubRight : virtual public Base {
public:
	int subRight_;
};
 
class Diamond : public SubLeft, public SubRight {
public:
	void func() {}
	int diamond_;
};
 
int main()
{
	Diamond diamond;
	cout << "sizeof Base: " << sizeof(Base) << endl;
	cout << "sizeof SubLeft: " << sizeof(SubLeft) << endl;
	cout << "sizeof Diamond: " << sizeof(Diamond) << endl;
	cout << "base_ offset: " << (size_t)&diamond.base_ - (size_t)&diamond << endl;
	cout << "subLeft_ offset: " << (size_t)&diamond.subLeft_ - (size_t)&diamond << endl;
	return 1;
}

编译环境是vs2019 x64,项目属性 => C/C++ => Command Line中增加

1
/d1reportSingleClassLayoutDiamond

编译时输出

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
1>class SubLeft	size(32):
1>	+---
1> 0	| {vbptr}
1> 8	| subLeft_
1>  	| <alignment member> (size=4)
1>	+---
1>	+--- (virtual base Base)
1>16	| {vfptr}
1>24	| base_
1>  	| <alignment member> (size=4)
1>	+---
1>class Diamond	size(56):
1>	+---
1> 0	| +--- (base class SubLeft)
1> 0	| | {vbptr}
1> 8	| | subLeft_
1>  	| | <alignment member> (size=4)
1>	| +---
1>16	| +--- (base class SubRight)
1>16	| | {vbptr}
1>24	| | subRight_
1>  	| | <alignment member> (size=4)
1>	| +---
1>32	| diamond_
1>  	| <alignment member> (size=4)
1>	+---
1>	+--- (virtual base Base)
1>40	| {vfptr}
1>48	| base_
1>  	| <alignment member> (size=4)
1>	+---
1>Diamond::$vbtable@SubLeft@:
1> 0	| 0
1> 1	| 40 (Diamondd(SubLeft+0)Base)
1>Diamond::$vbtable@SubRight@:
1> 0	| 0
1> 1	| 24 (Diamondd(SubRight+0)Base)
1>Diamond::$vftable@:
1>	| -40
1> 0	| &Diamond::{dtor}
1> 1	| &Diamond::func
1>Diamond::func this adjustor: 40
1>Diamond::{dtor} this adjustor: 40
1>Diamond::__delDtor this adjustor: 40
1>Diamond::__vecDelDtor this adjustor: 40
1>vbi:	   class  offset o.vbptr  o.vbte fVtorDisp
1>            Base      40       0       4 0

运行输出

1
2
3
4
5
sizeof Base: 16
sizeof SubLeft: 32
sizeof Diamond: 56
base_ offset: 48
subLeft_ offset: 8

refer to: https://blog.csdn.net/oracleot/article/details/5123657

This system (linux-x86_64) is not supported

编译openssl-1.1.0e时,报这个错,主要修改两处

Configure文件

1
2
3
#use if $^O ne "VMS", 'File::Glob' => qw/glob/;
# 修改为
use if $^O ne "VMS", 'File::Glob' => qw/:glob/;

test/build.info文件

1
2
3
use if $^O ne "VMS", 'File::Glob' => qw/glob/;
# 同样进行修改
use if $^O ne "VMS", 'File::Glob' => qw/:glob/;

refer to: https://www.jianshu.com/p/f011a24f2667

日语之奇怪的ある

“ある”对应基本意思是“有”,即“have”。但这句

1
森さんは学生ではありません。

译为“森先生不是学生”,“ある”表示的意思却是“是”,即“is”,“ではありません”是“ではない”的敬语形式。

那“森先生没有学生”该怎么说呢?

先来看“あります”和“います”的区别,
“あります”用于花、草、桌子等不具有意志的事物。
“います”用于具有意志的人、动物或昆虫。

1
2
いすが部屋にあります。
こどもは公園にいます。

再在《标日》中找例句

1
2
スミスさんの家にはプールがあります。
(わたしの)うちには子供がいません。

如此我们得到“森先生没有学生”的说法

1
2
森さんには本がありません。
森さんには学生がいません。

c语言疑难点

1,一个星号操作并一定代表一次内存寻址操作。指针指向的内存大小是指针指向的整个内存块大小,而数组变量指向的内存大小是其某个成员所占内存大小,数组变量的大小才是整个数组占用内存大小。

1
2
3
4
5
6
7
	// in x64 mode
	int a[][2] = { 5, 4, 3, 2, 1, 6 };
	int i1 = sizeof(a);		// i1 is 24
	int i11 = sizeof(*a);		// i11 is 8
	int i2 = **(a + 1);		// i2 is 3
	int i3 = **a + 1;		// i3 is 6
	int i4 = *((int*)a + 1);	// i4 is 4

对于某类型的指针p,p+1后的地址值是增加了sizeof(*p)。
对于数组a,a+1后的地址值是增加了sizeof(*a)。

2,++操作符不参入算术式内操作符之间的优化级打架,即使++操作符在括号操作符内,是不是很反直觉?

1
2
3
4
	int a[] = { 1, 2, 3, 4, 5 };
	int *p = a;
	int j = *p++; // j is 1
	int k = *(p++); // k is 2

3,关于字节对齐

1
2
3
4
5
6
struct Diamond {
	int a1;
	char a2;
	int64_t a3;
	char a4;
};

vc2019 x64和x86下都输出

1
2
3
4
5
6
7
1>class Diamond	size(24):
1> 0	| a1
1> 4	| a2
1>  	| <alignment member> (size=3)
1> 8	| a3
1>16	| a4
1>  	| <alignment member> (size=7)
1
2
3
4
5
struct Diamond {
	char a1;
	short a2;
	char a3;
};

vc2019 x64和x86下都输出

1
2
3
4
5
6
1>class Diamond	size(6):
1> 0	| a1
1>  	| <alignment member> (size=1)
1> 2	| a2
1> 4	| a3
1>  	| <alignment member> (size=1)

vector push_back后iterator还是否有效

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#include <vector>
 
using namespace std;
 
int main()
{
    vector<int> vec;
    vec.push_back(1);
    vec.push_back(2);
    vector<int>::iterator it = vec.begin();
    it++;
    for (int i = 5; i < 10000; i++)
        vec.push_back(i);
    int j = *it; //这里报错
    return 1;
}

实验证明:vector push_back后原来的iterator就失效了。

1
2
3
4
5
6
7
8
    list<int> li;
    li.push_back(1);
    li.push_back(2);
    list<int>::iterator itList = li.begin();
    itList++;
    for (int i = 5; i < 10000; i++)
        li.push_back(i);
    int result = *itList;

实验证明:list push_back后原来的iterator依然有效。
如此说明,iterator中存放的是成员的内存地址,而非成员相对基地址的位移。

UE4的TMap实现原理

TMap的成员ElementSetType是TSet类型,此TSet的成员是

1
TTuple<Key, Value>

TSet类由两个动态数组组成,一个用于Hash表,一个是TSparseArray。

先说TSparseArray,其成员Data是TArray类型,即动态数组,TSparseArray的特点是通过空闲成员内部指针将空闲成员链起来,这样可方便增加删除操作,但其中的增加操作的Index是无法预先指定的。

所以TSet类又用到了一个动态数组用于Hash表,这样可以计算Hash Key找到指定Hash表项,这个表项存的是Hash桶的最后一个入桶的成员在TSparseArray数组中的Index,而其它相同Hash Key的桶成员都在最后入桶成员结构内部链起来了。

判断类的继承性

比如类定义如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#include <memory>
#include <iostream>
 
using namespace std;
 
class BaseA
{
public:
	int i_;
};
 
class ChildA //: public BaseA
{
public:
	int i_;
};

如下的方法只会报编译错误

1
2
3
4
5
6
7
8
9
    ChildA *a = (ChildA *)1;
    if (NULL == static_cast<BaseA*>(a))
    {
        cout << "ChildA does not inherit from BaseA 2." << endl;
    }
    else
    {
        cout << "ChildA inherits from BaseA 2." << endl;
    }

如下的方法才能编译中自动检查类的继承性并作相应处理

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
template<class T, class = void>
struct IsFromBaseA : false_type {};
 
template<class T>
struct IsFromBaseA<T, void>
    : is_convertible<T*, BaseA*>::type {};
 
int main()
{
    if constexpr (conjunction_v<IsFromBaseA<ChildA>>)
    {
        cout << "ChildA inherits from BaseA." << endl;
    }
    else
    {
        cout << "ChildA does not inherit from BaseA." << endl;
    }
    return 1;
}

这是enable_shared_from_this实现的基础。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#include <memory>
 
using namespace std;
 
class Aa : public enable_shared_from_this<Aa> // 'public' is necessary.
{
public:
	shared_ptr<Aa> retThis()
	{
		return shared_from_this();
	}
};
 
int main()
{
	shared_ptr<Aa> p1 = make_shared<Aa>();
	shared_ptr<Aa> p2 = p1->retThis();
 
	p2.reset();
	p1.reset();
	return 0;
}

当p1在构造时,会检查Aa是否是enable_shared_from_this派生的类,如果是,则在enable_shared_from_this类中维护一个引用计数;如果不是enable_shared_from_this派生的,则在shared_ptr类中维护一个引用计数。

《旷野之息》中有趣的事情

  • 盾反的速度可以超过光速。
  • 中国人在喜事上吹唢呐,在悲事上也吹唢呐。我在《旷野之息》中打wetland的西诺克斯Hinox独眼巨人时听到了唢呐,同样我在一些韩国电影中也听到过唢呐。
  • 《旷野之息》里怪物会骑马,而人类在村中商店里公开售卖怪物的guts,是怪物野蛮,还是人类野蛮?
  • 在双子山,隔着屏幕,我起了同现实中一样的恐高反应,双脚发软不敢往下看。
  • 在双子山的神庙A记下了球阵的摆放位置,我就去神庙B成功地还原摆放位置完成神庙B的挑战,之后我认为神庙A的门也已打开可直接领取神庙A的精神球,于是头也不回过去了……
  • 既然红月是盖侬为了让怪物们起死回生而出现的,那么闪电一定是盖侬在打击林克。
  • 有人建议新人先不要玩旷野之息,说Link一个人太孤单了。而我认为从某个角度可把游戏分为几类,有一种是游戏内多人玩家一人,如《最终幻想》;有一种是游戏内一人玩家多人,如《旷野之息》。
  • 电视剧我只看历史或现实剧,而《旷野之息》都是虚构的,可我却觉得真香。石中剑?

还在玩……

春秋战国年表

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
      前868,	周夷王烹杀齐哀公吕不辰
 
前770-前770,	周平王东迁
 
前757-前701,	郑庄公/姬寤生/57/前743-前701/43/
 
前723-前645,	管仲
前???-前643,	齐桓公/小白/易牙,竖刁,开方
前697-前628,	晋文公/重耳/69/前636-前628/9/
前624-前607,	晋灵公/弹弓射行人,杀厨/鉏麑/赵盾
      前606,	王孙满对楚庄王/魑魅魍魉
      前605,	斗越椒之乱/狼子野心/若敖氏
前???-前605,	郑灵公/公子宋染指王八汤鼎
前???-前599,	陈灵公/夏姬/夏徵舒
前???-前554,	齐灵公/好女扮男装/晏子
前591-前541,	赵氏孤儿
前???-前531,	蔡灵侯/蔡景侯/楚灵王
前???-前529,	楚灵王/好细腰
前540-前493,	卫灵公/弥子瑕/子见南子
 
前571-前471,	老子
前559-前484,	伍子胥
前551-前479,	孔子
前547-前496,	阖闾/公子光/52/前515-前496/20/专诸刺王僚
前545-前470,	孙武/训练阖闾妃嫔
前???-前473,	夫差/前495-前473/23/干将莫邪
前???-前464,	勾践
前536-前448,	范蠡
 
前505-前425,	赵襄子/赵毋恤
前???-前415,	秦灵公/以君主妻河
 
前455-前395,	李悝/断讼以射
前440-前381,	吴起/杀妻/拒娶公主
      前379,	田氏代齐
      前376,	三家分晋
前400-前357,	田齐桓公/田午/扁鹊四见蔡桓公
前395-前338,	商鞅
前369-前286,	庄子
 
前372-前289,	孟子
前???-前316,	孙膑/围魏救赵,庞涓
前340-前295,	赵武灵王/胡服骑射/沙丘兵变
 
前???-前279,	齐孟尝君/田文
前???-前255,	范雎/远交近攻
前???-前257,	白起
前325-前251,	嬴稷/秦昭王/胁持赵胜替范雎报仇/灭周
前313-前238,	荀子
前280-前233,	韩非
前260-前260,	长平之战
前???-前251,	赵平原君/赵胜
前???-前243,	魏信陵君/魏无忌
前???-前238,	楚春申君/黄歇/李园
 
前230-前221,	秦灭六国
前259-前210,	秦始皇
前???-前208,	李斯

refer to:
https://history.sohu.com/20171230/n526739335.shtml

属性“NMakeBuildCommandLine”不存在

1
2
1>------ 已启动生成: 项目: Test01, 配置: XXX Win32 ------
1>C:\Program Files (x86)\Microsoft Visual Studio\2019\Professional\MSBuild\Microsoft\VC\v160\Microsoft.MakeFile.Targets(44,5): warning MSB8005: 属性“NMakeBuildCommandLine”不存在。  正在跳过...

原因是右键工程->属性->NMake->常规->生成命令行是空的。

请仔细审视编译输出日志,看编译对应的是哪种配置平台,如上例日志中对应的是Win32,则再查看Win32配置平台下的“生成命令行”是否为空。

或者发现编译的不是需要的配置平台,可通过“配置管理器”更正。

refer to: https://social.msdn.microsoft.com/Forums/vstudio/en-US/05c02dd5-4470-445f-8131-b993b482ff32/building-a-project-configuration-makefile?forum=vcgeneral