环境
VS2017 + C++14 语言的设置
class CA
{
public:
CA() { std::cout << "Class A" << std::endl; }; //无参构造函数
~CA() { std::cout << "Class A die..." << std::endl; };
};
class CB
{
public:
CB(void* pVOID = NULL) { std::cout << "Class B" << std::endl; }; //构造需要传递指向 void 类型的指针,默认为 NULL
~CB() { std::cout << "Class B die..." << std::endl; };
};
class CC
{
public:
CC(int* pLength = NULL) { std::cout << "Class C" << std::endl; } //构造需要传递指向 int 类型的指针,默认为 NULL
~CC() { std::cout << "Class C die..." << std::endl; };
};
void Test(void)
{
CA a0;
//CA a1 = new CA(); //缺少合适构造函数,使 CA* 转换为 CA
CA* a2 = new CA();
CB b0;
CB b1 = new CB(); //为什么这里就可以这么使用呢?并且从运行结果上看执行了两次 CB 的构造函数?
CB* b2 = new CB();
CC c0;
//CC c1 = new CC(); //缺少合适构造函数,使 CC*转换为 CC
CC* c2 = new CC();
delete a2;
//delete b1; //不是 CB*类型
delete b2;
delete c2;
}
1
wevsty 2018-10-27 19:18:19 +08:00
new CB();调用了第一次构造函数返回的类型是 CB*,所有的指针都可以转换为 void*类型,所以编译器帮你使用了 CB 的构造函数,把 new CB()得到的指针作为参数传递进去了,所以 b1 这个对象也不是 new 出来的,你当然也不能对他 delete。这个是隐性的数据类型转换导致的结果。
|
2
XuanFei990 OP @wevsty 1、调用了两次构造函数,是构造了两个完整的对象么?一次在堆中构造,一次在栈中构造?
2、作为参数传递进去,意思是在 CB 的构造函数中可以通过 pVOID 来访问到第一次构造的对象? 最近在看一个别的公司提供的一个操作 USB Device 的 API 源码,,构造函数就是形如这个的,只不过是用的 HANDLE,实际上也是通过 typedef 把 void*起了个别名,在测试的时候,发现这么写居然也可以通过编译 实际应用中,CB b1 = new CB();这种写法有什么后遗症么?? 正常应该使用 CB* b1 = new CB();这种方式对么? |
3
nicebird 2018-10-27 20:21:32 +08:00
CB b1 = new CB();
等价于 CB *temp = new CB(); CB b4(temp); 1. 发送了一次隐式转换,然后构造,为了防止这种现象使用 explicit 关键字。 2. temp 没有被释放掉。产生了内存泄漏。 |
4
justou 2018-10-27 20:28:42 +08:00
不该隐式转换的都尽量避免, 构造器加 explicit 修饰, 尤其是单参数的构造器.
后遗症就是容易出现这种隐式转换导致的各种奇怪 bug |
5
innoink 2018-10-27 20:42:37 +08:00
你只要搞明白,为什么第一个 new CB 内存泄漏了,就全明白了
|
6
XuanFei990 OP @justou 哦,这样,那明白了,,那就是这个 API,实际上是有潜在 bug,最好应该加上 explicit ?防止这种隐式转换是么?
|
7
XuanFei990 OP @nicebird 嗯,明白了,刚开始看高级特性,知道遇到的少了些。。。以前都是当 C 用的。。。
|
8
f4nyc 2018-10-27 23:11:04 +08:00 via iPhone
不是 ub 吗……
|