提问人:Tyler D 提问时间:9/17/2020 最后编辑:WaqarTyler D 更新时间:9/17/2020 访问量:1088
指针向量:为什么在外部更改指针不会更改向量元素?
Vector of pointers: Why does changing the pointer externally not change the vector element?
问:
请看下面的例子:
#include <iostream>
#include <string>
#include <vector>
class Base {
public:
virtual void price() const = 0;
};
class D1 : public Base {
public:
virtual void price() const {
std::cout << "Price of D1\n";
}
};
class D2 : public Base {
public:
virtual void price() const {
std::cout << "Price of D2\n";
}
};
int main()
{
std::vector<Base*> v;
Base* b = new D1();
v.push_back(b);
v[0]->price(); // "Price of D1\n" - OK!
b = new D2();
v[0]->price(); // "Price of D1\n"?! Why not "Price of D2\n"
}
一个简单的基类有两个派生类。在我的 我声明了一个包含指向基类的指针的向量,并用指向 的对象的指针填充它。main()
D1
当我更改为指向 D2 的指针时,为什么不相应地更改元素?他们不应该指向同一件事吗?b
b = new D2();
v[0]
答:
当我将 b 更改为指向 D2 的指针时,b = new D2();,为什么不相应地更改元素 v[0]?他们不应该指向同一件事吗?
因为将指针的副本存储在向量中。因此,如果您之后更改为指向其他内容,则不会对v.push_back(b);
b
b
v[0]
您可以简化它并像这样查看它:
int *ptr = new int;
int *ptr_copy = ptr;
*ptr = 2; //both *ptr and *ptr_copy have value: "2"
ptr = new int; //ptr now points to some other memory
*ptr = 5; //*ptr = 5, but *ptr_copy will still be "2"
现在,如果你真的希望在更改指针时也能反映这些变化,你需要另一个间接级别,即“指针到指针”:
int main()
{
std::vector<Base**> v; //vector of Base**
Base* b = new D1();
v.push_back(&b);
(*v[0])->price(); // "Price of D1\n" - OK!
b = new D2();
(*v[0])->price(); // "Price of D2\n"
}
评论
*b = d22
D2 d22;
D1
*b = d22
b
v[0]
int a = 10; float b = 1.;
a = b;
a
int
D1
v[0]->price()
D1
price()
delete
将释放 指向的内存。因此,如果 和 指向相同的位置(您尚未重新签署它们),则内存将被释放,并且两者都将指向无法访问的内存。b
b
v[0]
当您将指针插入到指针中时,会将该指针复制到容器中。后std::vector
std::vector<Base*> v;
Base* b = new D1();
v.push_back(b);
您有两个指向实例的指针:和 。现在,如果你继续D1
b
vec[0]
b = new D2();
你只覆盖这两个中的一个,这显然是 ,但不是 .因此,访问首先为您提供了对存储在那里的指针的引用。b
vec[0]
vec[0]
评论
*b = d22
D2 d22;
v[0] = b
b = new D2();
*b = d22;
D2 d22;
band
*b
*b = d22
我将尝试在较低的层面上解释它。
首先,了解指针本质上只是一个包含值的变量,而值恰好是内存中的地址。
让我们简化一下,假设每个类型都具有相同的大小,并且只有 5 个内存地址(在堆上)。(此外,我将忽略数组也将在堆上分配。
我们现在执行
Base* b = new D1();
假设分配的内存位于地址 3 处。 现在是一个仅保存值 3 的变量。我们的(堆)内存如下所示:b
0: ?
1: ?
2: ?
3: variable of type D1
4: ?
然后我们继续
v.push_back(b);
现在,数组包含一个值为 3 的条目。v
b = new D2();
我们现在分配了内存的新部分,假设在地址 1 处:
0: ?
1: variable of type D2
2: ?
3: variable of type D1
4: ?
b
现在存储这个地址,即 b 的值为 1。如果我们看一下,我们还没有改变它。它包含一个值为 3 的条目。v
v[0]->price();
这为我们提供了一个值为 3 的指针,我们取消引用并打印它。根据上面的内存映射,那里存储的是 D1 类型的变量。
这为你澄清了吗?
我还稍微扩展了您的代码,以使用实际地址来演示这一点:
http://www.cpp.sh/3s4b4
(如果您运行该代码,请注意,彼此之后分配的地址往往几乎相似,通常仅相差一位数,因此请仔细观察。例如,我得到了0x1711260和0x1711220。
如果你真的需要做你所期望的,你可以存储一个向量,并将地址存储在向量中:Base**
b
std::vector<Base**> v;
Base* b = new D1();
v.push_back(&b);
(*v[0])->price();
b = new D2();
(*v[0])->price();
http://www.cpp.sh/8c3i3 年实施。但如果你不是绝对需要,我不建议这样做,缺乏可读性和不必要的混淆。(请注意,在此示例中,第一个指针不会被删除,并且在更改后无法访问,因此我们会泄漏内存。b
试试这个变体
vector<int> v;
int b = 123;
v.push_back(b);
cout << v[0]; // prints 123
b = 456;
cout << v[0]; // still prints 123
希望这种变化不会改变是显而易见的,因为 的值是 的值的副本。但是,与您的代码进行比较,有什么区别?没有,完全一样的情况是复制的,改变不改变。您的案例涉及指针这一事实根本没有区别(在这方面),因为指针没有什么特别之处。b
v[0]
v[0]
b
v[0]
b
b
v[0]
评论
b
v[0] = new D2;