C++ C++;返回在堆上创建的对象并对其进行修改,不会更改它吗?

C++ C++;返回在堆上创建的对象并对其进行修改,不会更改它吗?,c++,pointers,c++14,memory-address,C++,Pointers,C++14,Memory Address,我有以下代码 #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;

我有以下代码

#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;
}
#包括
#包括
使用名称空间std;
结构foo{
结构条{
int foobar;
};
向量barp;
条形图和插入图(int v){
bar*b=新的bar();
(*b)foobar=v;
barp.推回(b);
返回*b;
}
无效编辑(条形图和条形图,整数v){
b、 foobar=v;
}
};
int main(){
福福;
foo::bar b=f.插入(5);
f、 编辑(b,10);

std::cout因为您是通过值而不是通过引用将参数传递给
edit()

edit()
最终修改了原始对象的副本,然后该副本立即被丢弃

此外,您还将从
insert()
返回记录的副本


您的
insert()
必须返回一个指针,而不是新记录的副本。您还必须传递一个指向
edit()
的指针。

因为您是通过值而不是通过引用将参数传递给
edit()

edit()
最终修改了原始对象的副本,然后该副本立即被丢弃

此外,您还将从
insert()
返回记录的副本

您的
insert()
必须返回指针,而不是新记录的副本。您还必须将指针传递给
edit()

b的地址是否与保存在f.barp[0]中的地址相同

不,不是。每次使用没有进一步限定条件的
bar
作为参数或返回类型时,您都要求制作副本。在这种情况下,这意味着
main
中的变量
b
edit
中的变量
b
都是副本

对于本玩具示例,您可以通过以下更改使程序执行预期的操作:

- 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++教材来解释“引用”。 (如果您以前从未见过上面的

-
/
+
符号,则表示“将标有减号的每一行替换为标有加号的对应行”。)

b的地址是否与保存在f.barp[0]中的地址相同

不,不是。每次使用没有进一步限定条件的
bar
作为参数或返回类型时,您都要求制作副本。在这种情况下,这意味着
main
中的变量
b
edit
中的变量
b
都是副本

对于本玩具示例,您可以通过以下更改使程序执行预期的操作:

- 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++教材来解释“引用”。 (如果您以前从未见过上面的

-
/
+
符号,则表示“将标有减号的每一行替换为标有加号的对应行”。)

b
与保存在
f.barp[0]
中的地址是否相同

不,它不是。您通过插入的值返回对象,即

bar insert(int v)
^^^
按值返回意味着复制:使用复制构造函数构造新的
,并丢弃原始条*

要获得预期的结果,请从
insert
返回
bar&

bar& insert(int v) {
// ^
}
类似地,
edit
如果希望所有函数都在同一对象上工作,则应通过引用获取其参数

*如果不是将指针存储在集合中,这也会造成内存泄漏。您的程序也存在内存泄漏,但您可以通过删除
barp
向量中的对象来修复它

foo::bar b = f.insert(5);
b
与保存在
f.barp[0]
中的地址是否相同

不,它不是。您通过插入的值返回对象,即

bar insert(int v)
^^^
按值返回意味着复制:使用复制构造函数构造新的
,并丢弃原始条*

要获得预期的结果,请从
insert
返回
bar&

bar& insert(int v) {
// ^
}
类似地,
edit
如果希望所有函数都在同一对象上工作,则应通过引用获取其参数

*如果不是将指针存储在集合中,这也会造成内存泄漏。您的程序也存在内存泄漏,但您可以通过删除
barp
向量中的对象来修复它

foo::bar b = f.insert(5);
此b对象与*f.barp[0]不同,因为它是根据返回的引用创建的。 若要使其正常工作,请将此行更改为

foo::bar& b = f.insert(5);
这样,您就创建了对刚刚插入到向量中的对象的引用

此b对象与*f.barp[0]不同,因为它是根据返回的引用创建的。 若要使其正常工作,请将此行更改为

foo::bar& b = f.insert(5);

这样,您就创建了一个对刚刚插入向量中的对象的引用。

您认为
return*b
做了什么?指向它的指针保存在f.barp中的对象,不是吗?
SuhDude555
b
与地址存储在
barp
中的对象不是同一个对象。想象一下它与任何其他类型:
intinsert(intv){int*b=newint();*b=v;barp.push_back(b);return*b;}
return*b
你相信什么呢?指针保存在f.barp中的对象,不是吗?
SuhDude555
b与地址存储在
barp
中的对象不是同一个对象。想象一下它与任何其他类型:
intinsert(intv){int*b=new int();*b=v;barp.push_back(b);return*b;}
edit
也应该引用。我建议
insert
返回一个指针,作为需要考虑引用对象的生存期的自文档。给定程序中存在内存泄漏。@BarryTheHatchet确实如此,但OP可以通过itera修复它