我有以下代码
#include <iostream>
#include <vector>
using namespace std;
struct foo {
struct bar {
int foobar;
};
vector<bar*> barp;
bar & insert(int v){
bar * b = new bar();
(*b).foobar = v;
barp.push_back(b);
return *b;
}
void edit(bar & b, int v){
b.foobar = v;
}
};
int main() {
foo f;
foo::bar b = f.insert(5);
f.edit(b, 10);
std::cout << (b.foobar == 10?"true":"false") << std::endl;//now ok
std::cout << (b.foobar == 5?"true":"false") << std::endl;//now ok
std::cout << ((*f.barp[0]).foobar == 10?"true":"false") << std::endl;//after edit, still returns false
std::cout << ((*f.barp[0]).foobar == 5?"true":"false") << std::endl;//after edit, returns true
return 0;
}
有人可以解释一下,为什么“b.foobar”不会改为10? b是否与f.barp [0]中保存的地址相同?
编辑:感谢您的回答,添加对void edit(bar&amp; b,int v)的引用当然有意义。但是添加对“bar&amp; insert”的引用似乎没有任何改变,因为(* f.barp [0])。foobar在编辑后保持不变,即使insert现在应该返回引用。
答案 0 :(得分:3)
b
的地址与f.barp[0]
中保存的地址相同吗?
不,它没有。您可以通过插入值按值返回对象,即
bar insert(int v)
^^^
按值返回意味着副本:使用复制构造函数构造新的bar
,并丢弃原始的 * 。
要获得您期望的结果,请从bar&
返回insert
:
bar& insert(int v) {
// ^
}
同样,如果您希望所有函数都在同一个对象上工作,edit
应该通过引用获取其参数。
* 如果不是将指针存储在集合中,这也会造成内存泄漏。您的程序也有内存泄漏,但您可以通过删除barp
向量中的对象来修复它。
答案 1 :(得分:1)
因为您按参数将参数传递给edit()
,而不是通过引用传递。
edit()
最终会修改原始对象的副本,然后立即被丢弃。
此外,您还要从insert()
返回记录的副本。
您的insert()
必须返回指针,而不是新记录的副本。您还必须将指针传递给edit()
。
答案 2 :(得分:0)
b是否与f.barp [0]中保存的地址相同?
不,它没有。 每次您使用bar
而没有其他资格作为参数或返回类型,您要求制作副本。在这种情况下,这意味着 b
中的变量main
和b
中的变量edit
都是副本。
对于这个玩具示例,您可以使程序按照您的预期执行这些更改:
- bar insert(int v){
+ bar &insert(int v){
- void edit(bar b, int v){
+ void edit(bar &b, int v){
- foo::bar b = f.insert(5);
+ foo::bar &b = f.insert(5);
如果您不明白这是做什么或为什么,请参阅C ++教科书以获得“参考”的解释。
(如果您之前从未见过上述-
/ +
符号,则表示“将标有减号的每一行替换为标有加号的相应行。”)< / p>
答案 3 :(得分:0)
foo::bar b = f.insert(5);
这个b对象与* f.barp [0]不同,因为它是从返回的引用中创建的。 要使其工作,请将此行更改为
foo::bar& b = f.insert(5);
这样您就可以创建对刚刚插入向量的对象的引用。