首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >除了存储地址外,如何实现指针?

除了存储地址外,如何实现指针?
EN

Stack Overflow用户
提问于 2010-10-15 06:11:31
回答 6查看 446关注 0票数 10

最近我回答了another question asking for My suggestion

代码语言:javascript
复制
Q: How does a pointer point to an object?
A: The pointer stores the address of that object.

但是user R..不同意我向Q建议的A-他说正确的答案是“它是特定的实现”。虽然当前的实现将数字地址存储为指针,但没有理由要做更详细的事情。

当然,我不能不同意,除了为了不同意而存储一个地址之外,还有其他的实现。我非常感兴趣的是,还有哪些其他真正使用过的实现。

除了在整数类型变量中存储地址外,在C++中其他实际使用的指针实现是什么?铸造(特别是dynamic_cast)是如何实现的?

EN

回答 6

Stack Overflow用户

发布于 2010-10-15 07:00:36

在概念层面上,我同意你的观点--我将对象的地址定义为“在内存中定位对象所需的信息”。然而,地址的样子可能会有很大的差异。

现在的指针值通常表示为一个简单的线性地址.但是,有些体系结构的地址格式并不那么简单,或者根据类型的不同而有所不同。例如,在x86上以实模式编程(例如在DOS下),有时必须将地址存储为段:偏移对。

有关更多示例,请参见http://c-faq.com/null/machexamp.html。我发现对Symbolics机器的引用很有趣。

票数 6
EN

Stack Overflow用户

发布于 2010-10-15 07:47:24

我会传唤Boost.Interprocess作为证人。

Boost.Interprocess中,进程间指针是从映射内存区域开始的偏移量。这允许从另一个进程获取指针,映射内存区域(哪个指针地址可能与传递指针的进程中的指针地址不同),并且仍然到达同一个对象。

因此,进程间指针并不表示为地址,而是可以解析为一个地址。

谢谢收看:)

票数 5
EN

Stack Overflow用户

发布于 2010-10-15 09:01:07

如果我们熟悉使用指针算法访问数组元素,那么很容易理解对象是如何放置在内存中的以及dynamic_cast是如何工作的。考虑以下简单的类:

代码语言:javascript
复制
struct point
{
    point (int x, int y) : x_ (x), y_ (y) { }
    int x_;
    int y_;
};

point* p = new point(10, 20); 

假设p被分配给内存位置0x01。它的成员变量存储在各自不同的位置,比如x_存储在0x04y_存储在0x07。将对象p可视化为一个指针数组比较容易。p (在我们的例子中(0x1) )指向数组的开头:

代码语言:javascript
复制
0x01
+-------+-------+
|       |       |
+---+---+----+--+
    |        |
    |        |
   0x04     0x07
 +-----+   +-----+
 |  10 |   | 20  |
 +-----+   +-----+

因此,访问字段的代码本质上将变成使用指针算法访问数组元素:

代码语言:javascript
复制
p->x_; // => **p
p->y_; // => *(*(p + 1))

如果语言支持某种类型的自动内存管理,比如GC,那么可以在场景后面的对象数组中添加额外的字段。假设有一个C++实现,它借助引用计数收集垃圾。然后编译器可能会添加一个额外的字段(rc)来跟踪这个计数。然后,上面的数组表示形式变成:

代码语言:javascript
复制
0x01
+-------+-------+-------+
|       |       |       |
+--+----+---+---+----+--+
   |        |        |
   |        |        |
  0x02     0x04     0x07
+--+---+  +-----+   +-----+
|  rc  |  |  10 |   | 20  |
+------+  +-----+   +-----+

第一个单元格指向引用计数的地址。编译器将发出适当的代码来访问应该对外部世界可见的p部分:

代码语言:javascript
复制
p->x_; // => *(*(p + 1))
p->y_; // => *(*(p + 2))

现在很容易理解dynamic_cast是如何工作的。编译器通过向底层表示添加额外的隐藏指针来处理多态类。这个指针包含另一个名为vtable的‘数组’开头的地址,后者又包含这个类中虚拟函数实现的地址。但是vtable的第一个条目是特殊的。它不是指向一个函数地址,而是指向一个名为type_info的类的对象。此对象包含对象的运行时类型信息和指向其基类的type_info的指针。请考虑以下示例:

代码语言:javascript
复制
class Frame
{
public:
    virtual void render (Screen* s) = 0;
    // ....
};

class Window : public Frame
{ 
public:
    virtual void render (Screen* s)
    {
        // ...
    }
    // ....
private:
   int x_;
   int y_;
   int w_;
   int h_;
};

Window的一个对象将具有以下内存布局:

代码语言:javascript
复制
window object (w)
+---------+
| &vtable +------------------+
|         |                  |
+----+----+                  |
+---------+     vtable       |            Window type_info    Frame type_info
|  &x_    |     +------------+-----+      +--------------+    +----------------+
+---------+     | &type_info       +------+              +----+                |
+---------+     |                  |      |              |    |                |
|  &y_    |     +------------------+      +--------------+    +----------------+
+---------+     +------------------+
+---------+     | &Window::render()|
+---------+     +------------------+    
+---------+                     
|  &h_    |
+---------+

现在,考虑一下当我们尝试将Window*转换为Frame*时会发生什么

代码语言:javascript
复制
Frame* f = dynamic_cast<Frame*> (w);

dynamic_cast将遵循w的vtable中的type_info链接,确认Frame在其基类列表中,并将w分配给f。如果在列表中找不到Frame,则f设置为0,表示转换失败。vtable提供了一种表示类的type_info的经济方法。这就是为什么dynamic_cast只适用于具有virtual函数的类的原因之一。从逻辑的角度来看,将dynamic_cast限制为多态类型也是有意义的。也就是说,如果一个对象没有虚拟函数,那么如果不知道它的确切类型,就不可能安全地操作它。

目标类型的dynamic_cast不一定是多态的。这允许我们将具体类型封装为多态类型:

代码语言:javascript
复制
// no virtual functions
class A 
{
};

class B
{
public:
    virtual void f() = 0;
};

class C : public A, public B
{
    virtual void f() { }
};


C* c = new C;
A* a = dynamic_cast<A*>(c); // OK
票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/3939876

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档