关于临时对象,热心人帮忙

时间:2022-09-06 21:24:31
StringBad是一个类,声明略。

StringBad metto(“hello”);
StringBad knot = metto;

C++ Primer Plus 中一书中说,knot是一个新创建的对象,被初始化为metto,因此使用
复制构造函数,但实现时也可能分两步来处理这条语句:使用复制构造函数创建一个临时
对象,然后通过赋值将临时对象的值复制到新的对象中。
问:在什么情况下创建一个临时对象,这个临时对象的析构函数什么时候被调用,也就是
什么时候内存被释放。
还有就是一般什么时候生成临时对象,在Bj的书中看到:如果x = y * z + t时,将生成一个临时对象
储存 y * z,这样的话如果x = y + z + t,是不是将生成一个临时对象储存y + z
谢谢

12 个解决方案

#1


StringBad metto(“hello”);
StringBad knot = metto;//我的个人意见是 ,只供看看用。先调用StringBad的缺省构造函数,在调用operator=贬值给knot

StringBad metto(“hello”);
StringBad knot(metto);  //调用拷贝构造函数初试化knot

再声明一次,、本人只当灌水用

#2


对咯,对咯,你真聪明。C++ Primer 讲得一点都没错。

其实你可以这样理解:= 是调用 operator =,+ 是调用 operator + 等等,只要这些运算操作函数的参数中传入了一个引用参数,并且这个参数是作为运算结果传进来的,这就意味着要生成一个临时变量。如果传入参数不是引用,例如 StringBad& operator = ( StringBad str );那么,再传入参数时还会再复制一个临时变量,总共两个。而如果 operator = 的返回类型也不是引用,为 StringBad operator = ( StringBad str ),那么返回时也将生成一个临时变量,然后这个返回的临时变量或变量的引用,再作为下一个运算操作函数的参数传入。

例如
StringBad a, b;
StringBad c = a + b;
那么步骤就是
1. 调用 a 的 StringBad operator + ( StringBad& str ) 参数 str = b 、*this = a,返回临时变量 a+b (由于不能更改 a 的值,所以必须分配新的存储空间)
2. 调用 c 的 StringBad& operator = ( StringBad& str ) 参数 str = 上一个 + 操作构造的临时变量 a+b 的引用,并且更改 *this 的值为 a+b,同时返回 *this 的引用,由于不是连等,没有人需要这个返回值,因此不须考虑。

同理,基本变量类型的运算也是遵从此规则,只不过其值的计算不是依靠函数,而是汇编咯。

#3


StringBad knot = metto 就等于 StringBad knot(metto)
是一样的。都只调用一次拷贝构造函数

#4


当函数返回一个对象时要产生临时对象(钱能语),看了上面的才知道很多地方都用,看来尽信书不如无书,呵呵。

#5


我想楼主说的两个都应该要调用构造函数来完成初始化的吧

#6


回复人: look01(^-^) ( ) 信誉:100  2004-09-28 14:34:00  得分: 0  
 
 
   当函数返回一个对象时要产生临时对象(钱能语),看了上面的才知道很多地方都用,看来尽信书不如无书,呵呵。
  
 
钱能说的是正确的,只要返回的不是引用,而是return by value,就会产生一个临时对象。

#7


还有,VC++.Net2003的编译器实现是第一种方式,楼主提到的第二种方式我没见过,而且我认为楼主提供的这段代码不可能按照第二种行为实现,很没有效率

如果是这样的代码,倒是符合第二个说法
struct A
{
/*...*/
};
A function(){A val;return val;}
A val=function();
这样的确会遭成临时对象的产生。

#8


自己在构造函数和析构函数里写输出信息看一看就知道了
在thinking in c++里描述得很详细

#9


现在通常
StringBad knot = metto;
是直接调用复制构造函数的,不会产生临时对象。
如果楼主对编译器表示怀疑项测试一下的话,可以自己写一个对象在构造函数和operator = 中输出信息

#10


临时对象的消亡点
对于这个问题好争论了好多年
在the Designe and evolution in c++中讲述比较详细
如何解决这个问题

我记得临时对象的析够在一个完整的语句结束之后

#11


真是奇怪,应该临时对象的创建要调用复制构造函数,
当临时对象被析构时,也应该调用析构函数
但是我下面的代码,并没有相应的输出?
class A
{
int m;
public:
A(){}
A(int x):m(x)
{
cout<<"constructing :"<<m<<endl;
}
A(A& a)
{
m=a.m;
cout<<"copy constructing: "<<m<<endl;
}
void change()
{
m++;
}
~A()
{
cout<<"deconstructing: "<<m<<endl;
}
};
A fn(A obj)
{
A x(obj);
obj.change();
x.change();
x.change();
return x;
}
int main()
{
A a1(7);
A a2(fn(a1));


return 0;
}
1.构造a1     
   construcing: 7
2.调用fn,复制构造obj
  copy construcing: 7
3.复制构造x(用obj)
  copy construcing: 7
4.复制构造临时对象,用以存储x
  copy construcing: 9 //这里也没有
5.析构x,obj  
   deconstrucing: 9
   deconstrucing: 8
6.复制构造a2
  copy construcing: 9
7.析构临时对象
   deconstrucing: 9//这里没有
8.析构a2,a1
   deconstrucing: 9
   deconstrucing: 7

#12


也就是似乎临时对象的创建与析构并没有正确输出?我用的是VC6

#1


StringBad metto(“hello”);
StringBad knot = metto;//我的个人意见是 ,只供看看用。先调用StringBad的缺省构造函数,在调用operator=贬值给knot

StringBad metto(“hello”);
StringBad knot(metto);  //调用拷贝构造函数初试化knot

再声明一次,、本人只当灌水用

#2


对咯,对咯,你真聪明。C++ Primer 讲得一点都没错。

其实你可以这样理解:= 是调用 operator =,+ 是调用 operator + 等等,只要这些运算操作函数的参数中传入了一个引用参数,并且这个参数是作为运算结果传进来的,这就意味着要生成一个临时变量。如果传入参数不是引用,例如 StringBad& operator = ( StringBad str );那么,再传入参数时还会再复制一个临时变量,总共两个。而如果 operator = 的返回类型也不是引用,为 StringBad operator = ( StringBad str ),那么返回时也将生成一个临时变量,然后这个返回的临时变量或变量的引用,再作为下一个运算操作函数的参数传入。

例如
StringBad a, b;
StringBad c = a + b;
那么步骤就是
1. 调用 a 的 StringBad operator + ( StringBad& str ) 参数 str = b 、*this = a,返回临时变量 a+b (由于不能更改 a 的值,所以必须分配新的存储空间)
2. 调用 c 的 StringBad& operator = ( StringBad& str ) 参数 str = 上一个 + 操作构造的临时变量 a+b 的引用,并且更改 *this 的值为 a+b,同时返回 *this 的引用,由于不是连等,没有人需要这个返回值,因此不须考虑。

同理,基本变量类型的运算也是遵从此规则,只不过其值的计算不是依靠函数,而是汇编咯。

#3


StringBad knot = metto 就等于 StringBad knot(metto)
是一样的。都只调用一次拷贝构造函数

#4


当函数返回一个对象时要产生临时对象(钱能语),看了上面的才知道很多地方都用,看来尽信书不如无书,呵呵。

#5


我想楼主说的两个都应该要调用构造函数来完成初始化的吧

#6


回复人: look01(^-^) ( ) 信誉:100  2004-09-28 14:34:00  得分: 0  
 
 
   当函数返回一个对象时要产生临时对象(钱能语),看了上面的才知道很多地方都用,看来尽信书不如无书,呵呵。
  
 
钱能说的是正确的,只要返回的不是引用,而是return by value,就会产生一个临时对象。

#7


还有,VC++.Net2003的编译器实现是第一种方式,楼主提到的第二种方式我没见过,而且我认为楼主提供的这段代码不可能按照第二种行为实现,很没有效率

如果是这样的代码,倒是符合第二个说法
struct A
{
/*...*/
};
A function(){A val;return val;}
A val=function();
这样的确会遭成临时对象的产生。

#8


自己在构造函数和析构函数里写输出信息看一看就知道了
在thinking in c++里描述得很详细

#9


现在通常
StringBad knot = metto;
是直接调用复制构造函数的,不会产生临时对象。
如果楼主对编译器表示怀疑项测试一下的话,可以自己写一个对象在构造函数和operator = 中输出信息

#10


临时对象的消亡点
对于这个问题好争论了好多年
在the Designe and evolution in c++中讲述比较详细
如何解决这个问题

我记得临时对象的析够在一个完整的语句结束之后

#11


真是奇怪,应该临时对象的创建要调用复制构造函数,
当临时对象被析构时,也应该调用析构函数
但是我下面的代码,并没有相应的输出?
class A
{
int m;
public:
A(){}
A(int x):m(x)
{
cout<<"constructing :"<<m<<endl;
}
A(A& a)
{
m=a.m;
cout<<"copy constructing: "<<m<<endl;
}
void change()
{
m++;
}
~A()
{
cout<<"deconstructing: "<<m<<endl;
}
};
A fn(A obj)
{
A x(obj);
obj.change();
x.change();
x.change();
return x;
}
int main()
{
A a1(7);
A a2(fn(a1));


return 0;
}
1.构造a1     
   construcing: 7
2.调用fn,复制构造obj
  copy construcing: 7
3.复制构造x(用obj)
  copy construcing: 7
4.复制构造临时对象,用以存储x
  copy construcing: 9 //这里也没有
5.析构x,obj  
   deconstrucing: 9
   deconstrucing: 8
6.复制构造a2
  copy construcing: 9
7.析构临时对象
   deconstrucing: 9//这里没有
8.析构a2,a1
   deconstrucing: 9
   deconstrucing: 7

#12


也就是似乎临时对象的创建与析构并没有正确输出?我用的是VC6