题目如下:问下列代码的打印结果为0吗?
#include
<
stdlib.h
>
#include
<
iostream
>
using
namespace
std;
struct
CLS
{
int
m_i;
CLS(
int
i ) : m_i(i){}
CLS()
{
CLS(
0
);
}
};
int
main()
{
CLS obj;
cout
<<
obj.m_i
<<
endl;
system(
"
PAUSE
"
);
return
0
;
}
打印结果是不定的,不一定为0
代码奇怪的地方在于构造函数中调用了自己的另一个构造函数
我们知道,当定义一个对象时,会按顺序做2件事情:
1)分配好内存(非静态数据成员是未初始化的)
2)调用构造函数(构造函数的本意就是初始化非静态数据成员)
显然上面代码中,CLS obj;这里已经为obj分配了内存,然后调用默认构造函数,但是默认构造函数还未执行完,却调用了另一个构造函数,这样相当于产生了一个匿名的临时CLS对象,它调用CLS(int)构造函数,将这个匿名临时对象自己的数据成员m_i初始化为0;但是obj的数据成员并没有得到初始化。于是obj的m_i是未初始化的,因此其值也是不确定的
从这里,我们归纳如下:
1)在c++里,由于构造函数允许有默认参数,使得这种构造函数调用构造函数来重用代码的需求大为减少
2)如果仅仅为了一个构造函数重用另一个构造函数的代码,那么完全可以把构造函数中的公共部分抽取出来定义一个成员函数(推荐为private),然后在每个需要这个代码的构造函数中调用该函数即可
3)偶尔我们还是希望在类的构造函数里调用另一个构造函数,可以按下面方式做:
在构造函数里调用另一个构造函数的关键是让第二个构造函数在第一次分配好的内存上执行,而不是分配新的内存,这个可以用标准库的placement new做到:
先看看标准库中placement new的定义
inline
void
*
__cdecl
operator
new
(size_t,
void
*
_P)
{
return
(_P);
}
可见没有分配新的内存。
正确的方式:
struct
CLS
{
int
m_i;
CLS(
int
i ) : m_i(i){}
CLS()
{
new
(
this
)CLS(
0
);
}
};
另: 若构造函数调用自身,则会出现无限递归调用,是不允许的
在c++编程规则101第56条说这种技巧简直就是在作孽。
题目如下:问下列代码的打印结果为0吗? #include &lt;stdlib.h&gt;#include &lt;iostream&gt;using namespace std;struct CLS{ int m_i; CLS( int i ) : m_i(i){} CLS() { CLS(0); }};int main(){...
在构造函数中
调用
另一个构造函数如果一不注意就会有无限递归的危险,而且构造函数的参数的不同也决定了
调用
的不同,所以特意总结了一下哪些形式的
调用
时允许的:
首先假设构造函数
调用
时参数都是外部的变量,而不是一个常量。
第一种,也是
C++
11支持的一种
调用
方式。在函数的初始化列表中
调用
另一个构造函数:
int b = 2;
class Test
public:
Test() : Test(b)
你看到的这个文章来自于http://www.cnblogs.com/ayanmw
由于最近写的代码 发现有点异常,值怎么是错误的呢?明明修改了的。
经过调试,发现原来 是构造函数里面的问题。
搜索:
c++
一个构造函数
调用
另一个 构造函数
发现,原来这就是一个普遍的问题,编译器也木有给警告,其实语法完全合理,如果是java的
首先明确一点:直接
调用
构造函数,只有一个作用,就是在栈上构造一个临时对象。<br />
所以构造函数的互相
调用
引起的后果不是死循环,而是栈溢出。理论上,不允许在某个构造函数中
调用
其他构造函数。除非有特别的功能需求。<br />
假设一个类<br />
class
A<br />
{<br />
public:<br />
A();<br />
A(int
i);<br />
~A();<br />
}<br />
假设实现是这样的:<br />
new
(this) T(t) 也叫做“
new
placement operator”。在括号中指定地址构造一个对象。例如copy赋值操作可以被下面的代码定义:
T& T::operator=( const T& other) {
if ( this != &other ) {
this->~T(); // li
在
C++
中,当你使用 `
new
` 运算符动态分配内存后,返回的是指向新分配内存的指针。`
new
` 关键字用于从内存堆中为某个数据类型创建一个新的对象,并返回一个对该对象的引用来表示其地址。例如:
```cpp
int* ptr =
new
int; // 分配一个整型变量的空间并返回指向它的指针
如果 `
new
` 成功,返回的是一个有效的指针;如果分配失败(比如内存不足),`
new
` 会抛出一个异常 `std::bad_alloc`。在这种情况下,你可以选择捕获这个异常并采取适当的清理措施,或者使用 `nothrow` 版本的 `
new
` 来避免异常:
```cpp
int* ptr =
new
(nothrow) int; // 如果内存分配失败,ptr将为nullptr
`return` 语句通常用于函数内部,当你想从函数中返回值或者对象的引用时,但请注意,如果你的函数返回的是动态分配的内存,记得要使用 `delete` 或者 `delete[]` 来释放内存,以防止内存泄漏:
```cpp
int* createObject() {
int* obj =
new
int;
// ... 对obj进行操作
return obj; // 返回指针
// 在函数外部
调用
时,需要删除内存
delete obj; // 错误的做法,因为对象可能已经超出作用域
正确的做法是在函数结束时手动释放内存,或者提供一个
析构函数
来处理这种情况:
```cpp
class MyClass {
public:
MyClass() { ... }
~MyClass() { delete this; } // 使用
析构函数
自动释放内存
MyClass* createObject() {
MyClass* obj =
new
MyClass;
// ... 对obj进行操作
return obj;
// 使用完后,由用户负责
调用
delete
delete obj; // 正确的做法