假设我有一个只包含对象的简单类:
class objholder{
object ojb;
public:
setobj(object o);
}
objholder::setobj(object o){
obj = o;
}
objholder::getobj(){
return obj;
}
假设我创建了一个创建object
实例的函数,然后将其传递给objholder
。
object
的实例会发生什么?它会持续存在吗? object
保存的objholder
实例,它会包含有效的引用会怎么样?以下是一些简单的函数,用于说明我上面描述的功能。
void foo(objholder oh){
object temp;
oh.setobj(temp);
}
void bar(objholder oh){
object temp = oh.getobj();
}
int main(int argc, char **argv){
objholder o;
foo(o);
bar(o);
}
答案 0 :(得分:3)
C ++是一种语言值语义,这意味着默认类型被视为值,复制等,而不像具有引用语义的Java或C#。让我们分析一下这个程序:
void foo( objholder );
int main(int argc, char **argv){
objholder o; // [1]
foo(o); // [2]
bar(o); // [3]
}
void foo( objholder oh ) { // [4]
object tmp; // [5]
oh.setobject( tmp ); // [6]
} // [7]
在[1]中,o
范围内创建了一个新对象main
。该对象包含按obj
默认构造函数初始化的类型为object
的子对象 objholder
。在[2]中,该对象的副本完成并传递给foo
([4]),创建一个传递给它的本地object
([5])。 [6]中setobject
的{{1}}成员方法,(请记住:oh
是oh
中objholder
的副本),因为main
按值获取元素,创建objholder::setobject
的副本,并将该副本传递给tmp
,然后创建副本并将其存储在成员属性中(未在代码中显示)。在[7]中,oh.setobject
的执行完成,所有局部变量以创建的相反顺序销毁,这意味着foo
被销毁,然后tmp
(这意味着oh
的内部副本被销毁。
此时我们回到tmp
我们的本地对象main
仍未触及 - 所有已处理的是传递给{{1}的副本 }。然后,在调用o
时,会创建一个副本并传递给foo
。
我开始注意到这是由于C ++中的 value 语义,与其他语言中的 reference 语义相比,如Java或C#。如果程序是(语法旁边)Java,在[2]和[3]中将传递引用的副本,并且引用的对象都在foo
,{{1}中和bar
会是一样的。这可以通过使用指针和引用在C ++中实现。 C ++引用不仅仅是Java / C#引用,所以如果你来自任何一种语言需要时间来理解相似之处和不同之处。
答案 1 :(得分:2)
函数返回时
object
的实例会发生什么?它会持续吗?
它与持有人一起被摧毁。但请注意,您的objectholder
副本对象已传递到setobj
。
如果我尝试访问由
object
保存的objholder
实例,它会包含有效的引用会怎么样?
你的意思是......
object obj;
{
objectholder holder;
holder.setobj(obj);
}
// do something to obj
?没有什么特别的事情发生(除非object
在其复制构造函数中做了一些特殊的事情)。
答案 2 :(得分:1)
你完成你的objholder的方式,你不是“持有”对象,只是持有对象的副本。
这只是复制'o'并将其存储在'obj'
中objholder::setobj(object o)
{
obj = o;
}
如果你想保留对象的引用,你需要传递引用或指向对象的指针
object& obj;
objholder::setobj(object& o)
{
obj = o;
}
然而,通过保持对象的引用,你仍然不是对象的所有者(如果我理解正确的是你得到的),你需要使用unique_ptr获取对象的所有权。通过使用unique_ptr,您可以传递一个对象。
说,为了理解对象的生命,你应该研究范围和免费存储/堆栈。