能否在已分配未构造的内存中直接使用类的数据成员?

tomtung 2008-07-30 10:17:24
rt...本来觉得答案肯定是否定的,但是看到C++ Primer第四版18.1.7实现的CachedObj类:



/* memory allocation class: Pre-allocates objects and
* maintains a freelist of objects that are unused
* When an object is freed, it is put back on the freelist
* The memory is only returned when the program exits
*/
template <class T> class CachedObj {
public:
void *operator new(std::size_t);
void operator delete(void *, std::size_t);
virtual ~CachedObj() { }
protected:
T *next;
private:
static void add_to_freelist(T*);
static std::allocator<T> alloc_mem;
static T *freeStore;
static const std::size_t chunk;
};

template <class T>
void *CachedObj<T>::operator new(size_t sz)
{
// new should only be asked to build a T, not an object
// derived from T; check that right size is requested
if (sz != sizeof(T))
throw std::runtime_error
("CachedObj: wrong size object in operator new");
if (!freeStore) {
// the list is empty: grab a new chunk of memory
// allocate allocates chunk number of objects of type T
T * array = alloc_mem.allocate(chunk);

// now set the next pointers in each object in the allocated memory
for (size_t i = 0; i != chunk; ++i)
add_to_freelist(&array[i]);
}
T *p = freeStore;
freeStore = freeStore->CachedObj<T>::next;
return p; // constructor of T will construct the T part of the object
}

template <class T>
void CachedObj<T>::operator delete(void *p, size_t)
{
if (p != 0)
// put the "deleted" object back at head of freelist
add_to_freelist(static_cast<T*>(p));
}

// puts object at head of the freelist
template <class T>
void CachedObj<T>::add_to_freelist(T *p)
{
p->CachedObj<T>::next = freeStore;
freeStore = p;
}

template <class T> allocator< T > CachedObj< T >::alloc_mem;
template <class T> T *CachedObj< T >::freeStore = 0;
template <class T> const size_t CachedObj< T >::chunk = 24;



其中add_to_freelist直接对未构造的内存进行使用……很奇怪对一个不存在的对象的成员进行操作为什么不会引起问题?
...全文
223 20 打赏 收藏 转发到动态 举报
写回复
用AI写文章
20 条回复
切换为时间正序
请发表友善的回复…
发表回复
cuidragoncui 2012-03-15
  • 打赏
  • 举报
回复
mark;
xie xie lou zhu;
cuidragoncui 2012-03-15
  • 打赏
  • 举报
回复
mark……
谢谢楼主;
xie;
tomtung 2008-08-02
  • 打赏
  • 举报
回复
谢谢指教~
tomtung 2008-08-02
  • 打赏
  • 举报
回复
好了结贴了……
yyyapple 2008-07-31
  • 打赏
  • 举报
回复
[Quote=引用 14 楼 tomtung 的回复:]
引用 12 楼 yyyapple 的回复:

这里的意思维护一个空闲内存链表,如果没有了空闲的,就重新分配一组,然后返回首个,对象然后在这个内存块中构建对象,delete后的内存块重新加入到空闲链表中

这句已经说了: return p; // constructor of T will construct the T part of the object



这点我明白。。。但即使是作为基类的CacheObj在这时也没有构造啊,next是它的成员,也是未经构造直接使用了啊……我只是不理解为…
[/Quote]

构造无非是在内存中初始化值,这里T是CacheObj的派生类,在freeList->CachedObj<T>::next用类名进行限制访问next成员,其实这样p->CachedObj<T>::next = freeStore也是构造了
tomtung 2008-07-31
  • 打赏
  • 举报
回复
[Quote=引用 13 楼 veloting 的回复:]
程序内存空间中分为静态数据区,代码区,栈区,堆区,其中static成员放在静态数据区,栈去里面一般放的是函数的内定义的变量,而堆区存放的是动态变量,一般用new,malloc创建的放在堆区里面。

静态数据区在编译期间就确定,栈区和堆区在程序的运行过程中会不断的变化!

你程序中那些变量是static的,在编译期间就确定地址和内存了,故可以使用!
[/Quote]

我指的是用allocator动态分配的内存……那个next不是static的……
tomtung 2008-07-31
  • 打赏
  • 举报
回复
[Quote=引用 12 楼 yyyapple 的回复:]

这里的意思维护一个空闲内存链表,如果没有了空闲的,就重新分配一组,然后返回首个,对象然后在这个内存块中构建对象,delete后的内存块重新加入到空闲链表中

这句已经说了: return p; // constructor of T will construct the T part of the object

[/Quote]

这点我明白。。。但即使是作为基类的CacheObj在这时也没有构造啊,next是它的成员,也是未经构造直接使用了啊……我只是不理解为什么给对象分配了空间以后在没有构造它之前就可以直接这样对成员进行操作。

而且在next被强行赋值以后,继承自CacheObj的类T也会在调用它自己的构造函数前调用CacheObj<T>的(自动生成的)构造函数,而这时候next已经有值了,不会有什么影响吗?

附CacheObj的使用方法:
[Quote=引用引用C++ Primer 4th Edition - 18.1.7. A Memory-Allocator Base Class:]

Using CachedObj
The only really tricky part in using CachedObj is understanding the template parameter: When we inherit from CachedObj, the template type we use to instantiate CachedObj will be the derived type itself. We inherit from CachedObj in order to reuse its freelist management. However, CachedObj holds a pointer to the object type it manages. The type of that pointer is pointer to a type derived from CachedObj.

[/Quote]
veloting 2008-07-31
  • 打赏
  • 举报
回复
程序内存空间中分为静态数据区,代码区,栈区,堆区,其中static成员放在静态数据区,栈去里面一般放的是函数的内定义的变量,而堆区存放的是动态变量,一般用new,malloc创建的放在堆区里面。

静态数据区在编译期间就确定,栈区和堆区在程序的运行过程中会不断的变化!

你程序中那些变量是static的,在编译期间就确定地址和内存了,故可以使用!
yyyapple 2008-07-31
  • 打赏
  • 举报
回复
[Quote=引用 7 楼 tomtung 的回复:]
引用 6 楼 yyyapple 的回复:
解释一下,add_to_freelist是个成员函数,没有构造对象之前当然不能用了,在运行期,对象构造好后,函数实际传递了一个this指针,就可以访问成员变量了;

代码只是些指令,真正要到运行期才执行


呃,我觉得add_to_freelist里的那些动作都是在“对象构造好”之前做的啊。比如operator new里面的:

C/C++ code
if (!freeStore) {
// the list is em…
[/Quote]

这里的意思维护一个空闲内存链表,如果没有了空闲的,就重新分配一组,然后返回首个,对象然后在这个内存块中构建对象,delete后的内存块重新加入到空闲链表中

这句已经说了: return p; // constructor of T will construct the T part of the object
tomtung 2008-07-31
  • 打赏
  • 举报
回复
[Quote=引用 10 楼 akirya 的回复:]
C/C++ code static void add_to_freelist(T*);
static std::allocator<T> alloc_mem;
static T *freeStore;
static const std::size_t chunk;


这不就是定义类静态成员变量。
[/Quote]
但内存不是动态分配的吗?
  • 打赏
  • 举报
回复
    static void add_to_freelist(T*);
static std::allocator<T> alloc_mem;
static T *freeStore;
static const std::size_t chunk;

这不就是定义类静态成员变量。
tomtung 2008-07-31
  • 打赏
  • 举报
回复
[Quote=引用 8 楼 iidioter 的回复:]
引用 2 楼 akirya 的回复:
静态的当然没问题了。


引用 3 楼 yyyapple 的回复:
静态数据成员在编译时期分配了
[/Quote]

为什么是静态的……
iBug168 2008-07-31
  • 打赏
  • 举报
回复
[Quote=引用 2 楼 akirya 的回复:]
静态的当然没问题了。
[/Quote]

[Quote=引用 3 楼 yyyapple 的回复:]
静态数据成员在编译时期分配了
[/Quote]
tomtung 2008-07-31
  • 打赏
  • 举报
回复
[Quote=引用 6 楼 yyyapple 的回复:]
解释一下,add_to_freelist是个成员函数,没有构造对象之前当然不能用了,在运行期,对象构造好后,函数实际传递了一个this指针,就可以访问成员变量了;

代码只是些指令,真正要到运行期才执行
[/Quote]

呃,我觉得add_to_freelist里的那些动作都是在“对象构造好”之前做的啊。比如operator new里面的:

if (!freeStore) {
// the list is empty: grab a new chunk of memory
// allocate allocates chunk number of objects of type T
T * array = alloc_mem.allocate(chunk);

// now set the next pointers in each object in the allocated memory
for (size_t i = 0; i != chunk; ++i)
add_to_freelist(&array[i]);
}


使用allocator的allocate成员分配未构造的内存,然后就直接调用add_to_freelist。而调用构造函数构造对象应该是在operator new执行完了以后的事吧?我觉得这时候内存里的对象还不存在……

而在operator delete里,也是把由析构函数销毁的已经不存在的对象交给了add_to_freelist这个static成员函数……

而primer里面对此只简单地说“After the call to add_to_freelist, each object on the freelist will be unconstructed, except for its next pointer...”

看来我还是没理解你的意思,能再详细解释一下吗?谢谢:)
yyyapple 2008-07-30
  • 打赏
  • 举报
回复
静态数据成员在编译时期分配了
  • 打赏
  • 举报
回复
静态的当然没问题了。
tomtung 2008-07-30
  • 打赏
  • 举报
回复


/* memory allocation class: Pre-allocates objects and
* maintains a freelist of objects that are unused
* When an object is freed, it is put back on the freelist
* The memory is only returned when the program exits
*/
template <class T> class CachedObj {
public:
void *operator new(std::size_t);
void operator delete(void *, std::size_t);
virtual ~CachedObj() { }
protected:
T *next;
private:
static void add_to_freelist(T*);
static std::allocator<T> alloc_mem;
static T *freeStore;
static const std::size_t chunk;
};

template <class T>
void *CachedObj<T>::operator new(size_t sz)
{
// new should only be asked to build a T, not an object
// derived from T; check that right size is requested
if (sz != sizeof(T))
throw std::runtime_error
("CachedObj: wrong size object in operator new");
if (!freeStore) {
// the list is empty: grab a new chunk of memory
// allocate allocates chunk number of objects of type T
T * array = alloc_mem.allocate(chunk);

// now set the next pointers in each object in the allocated memory
for (size_t i = 0; i != chunk; ++i)
add_to_freelist(&array[i]);
}
T *p = freeStore;
freeStore = freeStore->CachedObj<T>::next;
return p; // constructor of T will construct the T part of the object
}

template <class T>
void CachedObj<T>::operator delete(void *p, size_t)
{
if (p != 0)
// put the "deleted" object back at head of freelist
add_to_freelist(static_cast<T*>(p));
}

// puts object at head of the freelist
template <class T>
void CachedObj<T>::add_to_freelist(T *p)
{
p->CachedObj<T>::next = freeStore;
freeStore = p;
}

template <class T> allocator< T > CachedObj< T >::alloc_mem;
template <class T> T *CachedObj< T >::freeStore = 0;
template <class T> const size_t CachedObj< T >::chunk = 24;

yyyapple 2008-07-30
  • 打赏
  • 举报
回复
[Quote=引用 5 楼 tomtung 的回复:]
to2L3L:我是指CachedObj <T>::next
[/Quote]

解释一下,add_to_freelist是个成员函数,没有构造对象之前当然不能用了,在运行期,对象构造好后,函数实际传递了一个this指针,就可以访问成员变量了;

代码只是些指令,真正要到运行期才执行
tomtung 2008-07-30
  • 打赏
  • 举报
回复
to2L3L:我是指CachedObj<T>::next
wjb_yd 2008-07-30
  • 打赏
  • 举报
回复
内存都分配了,又没有别的进程跟它抢内存,淡然可以用了,只不过所有数据成员都没有初始化,值未定义而已

64,637

社区成员

发帖
与我相关
我的任务
社区描述
C++ 语言相关问题讨论,技术干货分享,前沿动态等
c++ 技术论坛(原bbs)
社区管理员
  • C++ 语言社区
  • encoderlee
  • paschen
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
  1. 请不要发布与C++技术无关的贴子
  2. 请不要发布与技术无关的招聘、广告的帖子
  3. 请尽可能的描述清楚你的问题,如果涉及到代码请尽可能的格式化一下

试试用AI创作助手写篇文章吧