| ||||
| 关键是我想知道背后的rationale,D&E上我记得没说。news group上的fellows一个劲的说不着调的话。我把帖子贴在下面,这个问题跟Pola上次发的自定义类相关new/delete代码有些关系,大伙说说看法 Why the inconsistent form of operator new/delete overloading? « 主题开始 « 前一页 9 个帖子中的第 1 个到第 9 个 后一页 » 主题结束 » 固定字体 - 可变宽字体 1 发件人: pon...@gmail.com - 查看个人资料 日期: 2006年2月26日(星期日) 下午7时54分 电子邮件: pon...@gmail.com 论坛: comp.lang.c++.moderated Not yet rated 评级: 显示选项 回复 | 答复作者 | 转发 | 打印 | 显示个别帖子 | 显示原始邮件 | 删除 | 报告滥用行为 | 查找此作者的帖子 As we all know, operator new()/new[]() can be overloaded and then called in new-expression. E.g. Suppose we have some sort of Fast Memory Pool, we could sketch something like this: void* operator new(size_t, FastMemory&); void operator delete(void*,FastMemory&); the usage of the overloaded new above would of course be: px = new (fast_mem) X; but then I got stucked on trying to use the seamingly absolutely natural way to delete px, that is: delete (fast_mem) px; // Here! Error Occurs! So why is this? And what's the alternative? Of course, I really wanna know the rationale behind this language rule, I would really appreciate your help, thanks in advance ![]() -- Regards! [ See http://www.gotw.ca/resources/clcm.htm for info about ] [ comp.lang.c++.moderated. First time posters: Do this! ] 回复 2 发件人: Thomas Richter - 查看个人资料 日期: 2006年2月27日(星期一) 上午12时44分 电子邮件: Thomas Richter <t...@math.tu-berlin.de> 论坛: comp.lang.c++.moderated Not yet rated 评级: 显示选项 回复 | 答复作者 | 转发 | 打印 | 显示个别帖子 | 显示原始邮件 | 报告滥用行为 | 查找此作者的帖子 - 隐藏被引用文字 - - 显示引用的文字 - pon...@gmail.com wrote: > As we all know, operator new()/new[]() can be overloaded and then > called in new-expression. > E.g. Suppose we have some sort of Fast Memory Pool, we could sketch > something like this: > void* operator new(size_t, FastMemory&); > void operator delete(void*,FastMemory&); > the usage of the overloaded new above would of course be: > px = new (fast_mem) X; > but then I got stucked on trying to use the seamingly absolutely > natural way to delete px, that is: > delete (fast_mem) px; // Here! Error Occurs! Which is invalid. The corresponding delete operation is delete px; and it the job of your operator delete() to find and fetch the memory pool the class has been allocated from. That is, you *must* overload operator delete(void *) plus its array form. The other operator delete is the "placement form" and it is only used if the constructor of an object calls the placement new operator and then fails to construct the object up to the end, in which case the corresponding operator delete will delete the left-over memory. > So why is this? operator new(size_t, mem) was originally intended to "place" objects into already allocated memory where this memory is passed as the second argument. Clearly, this memory would normally not require deletion - you would call the destructor, then throw the memory away in the same way you allocated it - outside the scope of the operator new/delete mechanism. > And what's the alternative? Overload the placement new, and the regular delete operator. Within operator new(x,y), allocate enough memory for the object and a pointer to the memory pool, keep care of alignment. Within operator delete(), fetch the pointer to the memory pool from the raw memory you got as argument, then call the release function of the pool. So long, Thomas [ See http://www.gotw.ca/resources/clcm.htm for info about ] [ comp.lang.c++.moderated. First time posters: Do this! ] 回复 Rate this post: Text for clearing space 3 发件人: ker...@mail.ru - 查看个人资料 日期: 2006年2月27日(星期一) 上午12时43分 电子邮件: ker...@mail.ru 论坛: comp.lang.c++.moderated Not yet rated 评级: 显示选项 回复 | 答复作者 | 转发 | 打印 | 显示个别帖子 | 显示原始邮件 | 报告滥用行为 | 查找此作者的帖子 Yes, that's true - you cannot pass additional arguments to operator delete. You should lookup you pool by object's address or save required information, e.g: void operator new(size_t s, FastMemory& m) { static const size_t ptr_size=sizeof(void*); void* p=m.allocate(s+ptr_size); reinterpret_cast<void*&> =&m;return p+ptr_size; } void operator delete(void* p,size_t s) { static const size_t ptr_size=sizeof(void*); FastMemory* m=reinterpret_cast<FastMemory*> ;m.deallocate(p-ptr_size,s+ptr_size); } So, each object allocated by FastMemory pool has that particular pool stated just before object's memory region starts. [ See http://www.gotw.ca/resources/clcm.htm for info about ] [ comp.lang.c++.moderated. First time posters: Do this! ] 回复 Rate this post: Text for clearing space 4 发件人: Jeffrey Schwab - 查看个人资料 日期: 2006年2月27日(星期一) 上午4时04分 电子邮件: Jeffrey Schwab <j...@schwabcenter.com> 论坛: comp.lang.c++.moderated Not yet rated 评级: 显示选项 回复 | 答复作者 | 转发 | 打印 | 显示个别帖子 | 显示原始邮件 | 报告滥用行为 | 查找此作者的帖子 ker...@mail.ru wrote: > void operator new(size_t s, FastMemory& m) The return type should be a pointer type, not void. > { > static const size_t ptr_size=sizeof(void*); > void* p=m.allocate(s+ptr_size); > reinterpret_cast<void*&> =&m;What is the purpose of this cast? > return p+ptr_size; Adding a size_t to a void* should be a compile-time error, since void does not have any size. This might work better: return static_cast<char*> +ptr_size;> } > void operator delete(void* p,size_t s) > { > static const size_t ptr_size=sizeof(void*); > FastMemory* m=reinterpret_cast<FastMemory*> ;> m.deallocate(p-ptr_size,s+ptr_size); The FastMemory* m is a pointer, so instead of m., you'll have to use m-> here. Also, p-ptr_size should not work for the same reason p+ptr_size does not work. You could ram something like this through the compiler: m->deallocate(static_cast<char*> -ptr_size,s+ptr_size);> } [ See http://www.gotw.ca/resources/clcm.htm for info about ] [ comp.lang.c++.moderated. First time posters: Do this! ] 回复 Rate this post: Text for clearing space 5 发件人: kanze - 查看个人资料 日期: 2006年2月27日(星期一) 下午7时20分 电子邮件: "kanze" <k...@gabi-soft.fr> 论坛: comp.lang.c++.moderated Not yet rated 评级: 显示选项 回复 | 答复作者 | 转发 | 打印 | 显示个别帖子 | 显示原始邮件 | 报告滥用行为 | 查找此作者的帖子 Jeffrey Schwab wrote: > ker...@mail.ru wrote: [...] > > return p+ptr_size; > Adding a size_t to a void* should be a compile-time error, since void > does not have any size. This might work better: > return static_cast<char*> +ptr_size;This still leaves open the possibility (probability, on a 32 bit machine) that the resulting pointer is not sufficiently aligned. -- James Kanze GABI Software Conseils en informatique orientée objet/ Beratung in objektorientierter Datenverarbeitung 9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34 [ See http://www.gotw.ca/resources/clcm.htm for info about ] [ comp.lang.c++.moderated. First time posters: Do this! ] 回复 Rate this post: Text for clearing space 6 发件人: pon...@gmail.com - 查看个人资料 日期: 2006年2月27日(星期一) 下午10时00分 电子邮件: pon...@gmail.com 论坛: comp.lang.c++.moderated Not yet rated 评级: 显示选项 回复 | 答复作者 | 转发 | 打印 | 显示个别帖子 | 显示原始邮件 | 删除 | 报告滥用行为 | 查找此作者的帖子 ker...@mail.ru wrote: > void operator delete(void* p,size_t s) > { > static const size_t ptr_size=sizeof(void*); > FastMemory* m=reinterpret_cast<FastMemory*> ;> m.deallocate(p-ptr_size,s+ptr_size); > } I do not think this is the right way. How do you presume that all the chunks passed to operator delete has the same book-keeping structure? That is, if we now pass some regular allocated memory chunk to operator delete, like this: int* p = new int; delete p; // of course p doesn't point somewhere in FastMemory area, but the overloaded operator delete() above treats it as one, and try to "reinterpret_cast<FastMemory*>(p-ptr_size)", how could this succeed as long as p doesn't point somewhere in FastMemory pool? In a word, I don't think this alternative is "the" alternative. And I strongly hope to know why the language forbids the seemingly natural way to do this(that is, delete (fastMem) p ? Is there something wedon't know? P.S. The second alternative is imperfect, too. It's highly inconsistent.Don't you think? [ See http://www.gotw.ca/resources/clcm.htm for info about ] [ comp.lang.c++.moderated. First time posters: Do this! ] 回复 7 发件人: RenjithMohan - 查看个人资料 日期: 2006年2月28日(星期二) 上午12时45分 电子邮件: "RenjithMohan" <renjithmo...@hotmail.com> 论坛: comp.lang.c++.moderated 跟帖发送至: comp.lang.c++.moderated Not yet rated 评级: 显示选项 回复 | 答复作者 | 转发 | 打印 | 显示个别帖子 | 显示原始邮件 | 报告滥用行为 | 查找此作者的帖子 pon...@gmail.com wrote: >but then I got stucked on trying to use the seamingly absolutely >natural way to delete px, that is: >delete (fast_mem) px; // Here! Error Occurs! Here the error occurs since there is no such thing as a placement delete operator. So in order to achieve this you will have to call the form of your delete operator.But before that you are supposed to call the dtor of the class like this px->~X; //call the dtor X: perator delete(px, fast_mem);This will really call your overloaded delete operator. The code inside your delete operator is really implementation dependent . It depends on how you want the pool to behave. Most probably you would be just marking one of your allocated nodes as allocable rather than giving it back to the memory manager of the OS. [ See http://www.gotw.ca/resources/clcm.htm for info about ] [ comp.lang.c++.moderated. First time posters: Do this! ] 回复 Rate this post: Text for clearing space 8 发件人: Ron Natalie - 查看个人资料 日期: 2006年2月27日(星期一) 上午4时06分 电子邮件: Ron Natalie <r...@spamcop.net> 论坛: comp.lang.c++.moderated Not yet rated 评级: 显示选项 回复 | 答复作者 | 转发 | 打印 | 显示个别帖子 | 显示原始邮件 | 报告滥用行为 | 查找此作者的帖子 pon...@gmail.com wrote: > but then I got stucked on trying to use the seamingly absolutely > natural way to delete px, that is: > delete (fast_mem) px; // Here! Error Occurs! There's no such thing as a placement delete expression. The only time the non-default deallocation function is called is when an exception happens during object creation. Your choices are either: 1. Make your default deallocation function smart enough to notice stuff allocated with the placement new and do the right thing. 2. Explicitly call the destuctor and do what ever you need to delete "fast_mem" (possibly in a function): template <class T> void DeleteFastMem(T* t) { t->~T(); // reclaim t here. } [ See http://www.gotw.ca/resources/clcm.htm for info about ] [ comp.lang.c++.moderated. First time posters: Do this! ] 回复 Rate this post: Text for clearing space 9 发件人: Kodt - 查看个人资料 日期: 2006年2月27日(星期一) 下午6时43分 电子邮件: "Kodt" <nickolay.mer...@gmail.com> 论坛: comp.lang.c++.moderated Not yet rated 评级: 显示选项 回复 | 答复作者 | 转发 | 打印 | 显示个别帖子 | 显示原始邮件 | 报告滥用行为 | 查找此作者的帖子 - 隐藏被引用文字 - - 显示引用的文字 - pon...@gmail.com wrote: > As we all know, operator new()/new[]() can be overloaded and then > called in new-expression. > E.g. Suppose we have some sort of Fast Memory Pool, we could sketch > something like this: > void* operator new(size_t, FastMemory&); > void operator delete(void*,FastMemory&); > the usage of the overloaded new above would of course be: > px = new (fast_mem) X; > but then I got stucked on trying to use the seamingly absolutely > natural way to delete px, that is: > delete (fast_mem) px; // Here! Error Occurs! > So why is this? And what's the alternative? > Of course, I really wanna know the rationale behind this language rule, > I would really appreciate your help, thanks in advance ![]() The alternative is to call destructor and operator delete separately: template<class T> void delete_fastmem(FastMemory& fast_mem, T* ptr) { if(!ptr) return; ptr->~T(); operator delete(ptr, fast_mem); } Another alternative is to assert that there is only one fast_mem in the system, and overload operator new and delete for given class class Some { public: static void* operator new(size_t n) { return alloc_at_fastmem(n); } static void operator delete(void* p) { free_at_fastmem ; }....... }; that makes common forms of new/delete expressions to use your allocator. [ See http://www.gotw.ca/resources/clcm.htm for info about ] [ comp.lang.c++.moderated. First time posters: Do this! ] 回复 Rate this post:
__________________ C++的罗浮宫: http://blog.csdn.net/pongba TopLanguage http://groups.google.com/group/pongba |
| ||||
| 这里所讨论的placement new和placement delete应当是全局的, 通用的. placement new的语法: void* new(size_t size, void* p); placement new可以将对象构建在用户所指定的任意一块内存区域上(堆, 栈,...). 假设的placement delete语法: void delete(void*p, void* mem); placement delete, 不是不想提供, 而是无法提供. 编译器显然没有用户清楚该块内存的来历. 他拿到这块内存后, 问题在于如何释放? 传入的第二个参数, 根本没有告诉他除了地址以外的任何信息, 这一点和placement new完全不一样, 他只是接受一个已经构建好的内存区域的地址而已,自己不做分配的. 这就是通用placement的弊病, 既然你通用, 那就无法获取特定的信息. 只能让用户自己去进行这个动作. |
| ||||
| 我觉得这本来就是Bjarne Stroustrup怪癖惹的祸。B.S.比较喜欢把原来的东西解释出新的意思,然后以此避免加入关键词。 本来new包含了两层语义,也就是所谓的operator new和new operator。前者分配内存,后者调用ctor。对于一个C++用户来说,他/她/它能够控制前者,但是不能控制后者。 其实直到这里,还是很正常的,但是后来有人说,C++里面,我无法直接调用ctor呀。为了满足这个要求,必须加入一个机制。但是直接调用ctor的语法和别的容易冲突,如果专门加一个新的语法要素,譬如说 ctor( SomeClass, p );// 相当于p->SomeClass::SomeClass() B.S.会很不喜欢的。因此,最后加了一个placement new。placement new把new本身的语义脱离开了。也就是说,new的过程,不再是那么“自动”。 placement new之所以能够这样做,是因为它的上下文是可以控制的,说得更粗鲁一点,因为它本身“没责任”,也就是说,它不用确认这个内存是否合法,长度是否够,是否对齐,...。所以,我可以写一个函数,接受一个p作为参数,在这上面placement new一个新对象,然后返回,美其名曰为“in place factory” ![]() 为什么没有placement delete,因为从需要上来说,我们可以直接调用dtor,也就是说,对dtor的直接调用部分体现了placement delete。为什么无法实现placement delete呢?这我觉得分两种情况考虑。第一种就是这个指针的上下文是已知的,那么,我不需要placement delete也可以活下去,甚至活得不差。其次,如果这个上下文是未知的,我是不能像placement new那样不负责任的进行delete的,所以这种情况下,无意义。进一步的想,如果有placement delete,我们能够获得什么好处吗?不能,因为保持形式上一致最大的原因是for GP,但是这里形式上已经不一致了,GP不能用。 其实,如果ctor是可调用的,placement new也没什么意义的 ![]() |
| ||||
| Bjarne是不是有怪癖我不知道,不过猫老大(现在是不是该改名叫骷髅猫老大? )的话我基本上同意。另外,我建议大家是不是可以想得再多一点:1. 这个placement new在工程开发中能用在哪些地方?在我的印象里,除了在STL容器内部见过这个东西之外,我基本上没有在其它任何地方见过这个东西。大家能举出其他的例子么? 2. placement delete这个玩意到底在实际程序中有多少作用?按照经典的做法,placement delete的作用是在“placement new构造对象失败时自动调用”的,换句话说,它符合猫老大的“不能控制”一说,只是这时候我们不能控制的是free()或者::delete(),那么,我们可以保证自己编写的placement delete的合法性么?比如,为什么我们不能这样: c++ 代码:
我倒觉得让程序员自己来保证访问的合法性比用placement delete更好一点。 |
| ||||
| 回复太长,没耐心看完了。guru们说的好像也就是我们在另外一个帖子里讨论的东西。placement delete的功能: 代码:
|
| ||||
| 实际上我还有些问题不明白, void* HeapZone = std::malloc(1024); MyClass* ptr1 = new (HeapZone) MyClass; MyClass* ptr2 = new (HeapZone) MyClass; 这个ptr1跟ptr2的地址会一样, 也就是placement new并没有提供任何自动管理的机制, 还是需要自己来管理, 这样如果要实现一个如List的数据结构, 必需自己记录预先开辟的内存使用情况, 有谁读过STL allocator的源码? STL是怎么在指定的开辟好的内存上allcate多次内存并记录预先开辟内存的使用情况的? |
| ||||
| 引用:
你用placement new本来内存就要自己管理. 因为placement new接受的内存又未必只是heap的, 可以来自静态存储区, 或者一个stack. 这个placement new的就是个通用的, 能够对任意给你的内存区域进行初始化构建工作的. 但是这个内存的管理, 只有用户最清楚. 如果这个内存是static或者stack的, 你难道指望new和delete去给你自动管理? |
| ||||
| 引用:
如果要构建一个共享内存的Map, allocator还是要自己记录内存使用情况。 这一种应该可以提供一种统一的记录机制, 提供给allocator起始地址以及size, 然allocator来用自己的结构记录使用情况比较好,不知道有没有人实现过 |