在我的代码中,我有:
#define EV( event ) SendEvent( new event );
EV( evFormat );
但是我想在EV
宏中传递一个创建的对象,如:
CEvent *ev = new CEvent();
EV( ev );
这可能吗?因为我没有办法修改EV
宏
#define EV( event ) SendEvent( new event ); // Can't be changed.
宏强制每次调用SendEvent
都应该创建一个新的动态对象。你的问题不只是使用宏是愚蠢的,例如降低了你的源代码的可读性。此外,宏不允许您在调用之前创建对象,并且您不能更改宏;用你的话来说,"我没有办法修改EV
宏"。
因此解决方案很简单:
不要使用宏,直接使用SendEvent
,记住不要使用delete
。
当前编写EV
的方式,它将在每次调用时生成一个新对象。但是创建的对象不一定要与最终传递给SendEvent的对象类型相同。这是因为预处理器宏的文本性质和更复杂的表达式增加了一些技巧。想想看:
class dummy {
private:
static dummy* freeme;
public:
dummy() { freeme = this; }
static bool dofree() { delete freeme; return true; }
};
dummy* dummy::freeme;
CEvent *ev = new CEvent(this);
EV( dummy && dummy::dofree() ? ev : NULL );
这将展开,所以你正在运行的新不是一个CEvent,而是一个虚拟类…然后释放它,然后整个表达式求值为事件:
SendEvent( new dummy && dummy::dofree() ? ev : NULL );
(注意:使用?:不如逗号操作符好,所以这里浪费了一个NULL分支,实际上从来没有发生过。逗号操作符很好,但是预处理器宏对逗号有特殊的处理,这是不能使用逗号的情况之一。使其线程安全留给读者作为练习。)
为了使它"更干净",但仍然用EV
来表达…不用显式地提到SendEvent
,您就可以创建自己的宏:
#define EV2(event) EV( dummy && dummy::dofree() ? event : NULL )
…或者你可以直接使用SendEvent,因为它似乎可以完全满足你的需求。但这有什么好玩的呢?; p
更新:
正如@AlfPSteinbach指出的那样,将new
变成无op的一种更深奥但轻量级的方法是使用新的位置:
int dummy;
CEvent *ev = new CEvent(this);
EV( (&dummy) int ? ev : NULL );
现在扩展为:
SendEvent( new (&dummy) int ? ev : NULL );
你正在执行一个new,但是这次不用担心释放结果!因为我不完全确定这是否合适,特别是在线程的情况下,我提出了自己的问题:
在同一地址多次放置-new是否定义良好/合法?
完全可行,无需更改宏。这太冒险了。注意,您必须设置delete []
#include <memory>
struct CEvent {};
void SendEvent(CEvent*) {}
#define EV( event ) SendEvent( new event );
int main() {
char *cev = new char[sizeof(CEvent)];
CEvent* ev = (CEvent*)cev;
EV( (ev)CEvent );
ev->~CEvent();
delete [] cev;
}
http://ideone.com/您可能会泄漏内存,除非SendEvent从内部管理它,例如
void SendEvent(const Event *ev) {
doSendEvent(ev);
delete ev;
}
把这个放在一边,你试过了吗,应该可以的
EV(CEvent)
如果没有,可以为CEvent类重新定义operator new,这样上面的调用就可以工作了。
但是你的问题真的很不寻常。你确定你走的路对吗?
如果没有办法修改EV
宏,那么这是不可能的。你不能创建自己的宏,SendEvent( event );
代替?
更新:是否有可能#undef
原始宏,并提供您自己的定义?假设您只想要新的行为,您可以使用
#undef EV
#define EV( event ) SendEvent( event );
但是现在你需要用EV( new event )
代替原来的调用类型