热度 9
2011-12-6 10:37
1602 次阅读|
0 个评论
The C++ Standard states that placement allocation functions are reserved, and a C++ program may not define functions that displace the versions in the Standard C++ library. 8 However, a program can overload the placement allocation functions. As diligent reader willc2010 observed in an online comment, "there doesn't seem to be anything to prevent someone from defining this: void * operator new(std::size_t count, timer_type *p) { do_something ; return some_value ; } which can completely, and silently, change the behaviour." Here's why this is a potential problem. You can define a pointer to the timer registers as: timer_type *const the_timer = reinterpret_cast (0xFFFF6000); then initialise the timer using a placement new expression: new (the_timer) timer_type; The compiler selects the placement operator new whose second parameter type most closely matches the type of the placement argument. In this case, compiler selects the overloaded placement new because its second parameter has the same type as the placement argument, the_timer , namely "pointer to timer_type ". Defining operator new as a class member avoids any problems caused by an inappropriate overloading of global placement new . When the compiler sees a new-expression as in: the_timer = new timer_type; it looks first for an operator new that's a member of class timer_type . If the compiler finds any member operator new , it stops looking and never considers any operator new declared globally. In this case, the compiler finds a member declared as: void *operator new(std::size_t); and uses it to compile the new-expression just above. Since timer_type 's member operator new has no placement parameters, a placement new-expression such as: new (the_timer) timer_type; simply won't compile. If you define a usual (non-placement) operator new as a member of class timer_type , and you still want to be able to use placement new-expressions with timer_type , you must define both usual and placement operator new as class members, as in: class timer_type { public: ~~~ void *operator new(std::size_t) { return reinterpret_cast (0xFFFF6000); } void *operator new(std::size_t, void *p) { return p; } ~~~ }; More to come The member operator new defined just above works just fine when you have only one timer. When you have multiple timers at distinct addresses, you need to do something else. Of course, you can always define a placement operator new as a member, but then you don't get guaranteed initialisation. In a future column, I'll consider ways to augment member operator new so that it supports multiple instances of a device. Endnotes: 1. Saks, Dan. "Alternative models for memory-mapped devices," Embedded Design India , March 2011. http://forum.embeddeddesignindia.co.in/BLOG_ARTICLE_6981.HTM. 2. Saks, Dan. "Memory-mapped devices as C++ classes," Embedded Design India , March 2011. http://forum.embeddeddesignindia.co.in/BLOG_ARTICLE_7022.HTM 3. Saks, Dan. "Compared to what?," Embedded Design India , March 2011. http://forum.embeddeddesignindia.co.in/BLOG_ARTICLE_7029.HTM. 4. Saks, Dan. "Demystifying constructors," Embedded Design India , April 2011. http://forum.embeddeddesignindia.co.in/BLOG_ARTICLE_7113.HTM. 5. Saks, Dan. "Constructors and object definitions," Embedded Design India , April 2011. http://forum.embeddeddesignindia.co.in/BLOG_ARTICLE_7323.HTM. 6. Saks, Dan. "Issues when constructing memory-mapped objects," Embedded Design India , August 2011. http://forum.embeddeddesignindia.co.in/BLOG_ARTICLE_8898.HTM. 7. Saks, Dan. "Learn about new with placement," Embedded Design India , September 2011. http://forum.embeddeddesignindia.co.in/BLOG_ARTICLE_9401.HTM. 8. ISO/IEC Standard 14882:2003(E), Programming languages – C++.