posts - 16,  comments - 34,  trackbacks - 0
共10页: First 2 3 4 5 6 7 8 9 10 
re: 对malloc的返回值应该如何转型 OwnWaterloo 2009-03-17 21:10
@C++ Beginner
强制转换都不会触发构造函数。

 
static_cast用于隐式转换过程,如:
short s; int i;
= s; //可以,向更宽整数类型进行隐式转换。
= i; //警告,向更窄整数类型转换。
= static_cast<short>(i); //过程,明确表明代码作者的意图,警告消除。
 
base* b; derived* d;
= d; // 可以,向上转型,隐式转换。
= b; // 错误,向下转型,不允许。
= static_cast<derived*>(b); // 可以,向上转型的过程。但不保证正确
 
object* o; void* p;
= o; // 可以,任何指针类型都可以隐式转换到void*
= p; // 过程是错误,除非
= static_cast<object*>(o); // 可以,但不保证正确
 
 
reinterpret_cast用于整数和指针之间,无继承关系的指针之间的转换。
按照其二进制表示,重新解释(Re-Interpret),如:
T* p; intptr_t i;
= reinterpret_cast<intptr_t>(p);
// 将p的地址,解释成一个整数。
= reinterpret_cast<T*>(i);
// 将i的值,解释成一个指向T的指针。
 
T1* p1; T2* p2;
p1 
= reinterpret_cast<T1*>(p2);
// 将p2中保存的地址的值,复制到p1。
// 因为p1是T1*类型的指针,以后对p1的操作,将按T1*来解释

// 另外一种方式:
p1 = static_cast<T1*>static_cast<void*>(p2) );
过段时间把3个“to do”补完了再发你。
@陈梓瀚(vczh)
---------------------------------------------
如果不兼容的话,怎么调API?所以必须兼容。
---------------------------------------------
---------------------------------------------
虽然我也觉得其他编译器也应该是这样。
没有理由无故的与楼主描述的__cdecl,__stdcall实现不兼容。
---------------------------------------------
我想说的就是这个意思,应该不会有编译器放弃大多数旧有的C目标文件遵守的约定,另寻它法。


但是呢。。。 还是不像有个ISO那么有把握。


http://www.unixwiz.net/techtips/win32-callconv.html
这篇文章里说了一个入栈顺序,和平时所说的右到左不同。
但在win32上结论是一样的。

@陈梓瀚(vczh)
MSDN就是微软的编译器了。

其他的编译器是否也是这样?

虽然我也觉得其他编译器也应该是这样。
没有理由无故的与楼主描述的__cdecl,__stdcall实现不兼容。

但是心里没谱啊 ……
楼主作过其他编译器的调查么?
有前人作过类似的调查么?
@陈梓瀚(vczh)
老兄 你说的是WndPorc吧? WndPorc拿到HWND,然后去查表找this。
上面说了,这是MFC和wxwidgets处理WndProc的方式。

对于HOOK,即使通过LPARAM转型到XXXStruct,拿到一个HWND,也不能保证就有user data。
比如,程序已经是别人写好了,根本无法知道他是否有表。
这时候,就必须HOOK自己想办法找user data了。
--------------------------------------------------------------------------------------------
stdcall、cdecl和fastcall的参数都是从右到左入栈,并且返回值遵循以下规律:
    小于等于4字节结构用EAX
    小于等于8字节结构用EDX:EAX
    浮点数用ST(0)
    其他则在EAX放置一个指针,供返回值使用
--------------------------------------------------------------------------------------------
 
请问一下,关于这个规律,是有标准规定的吗?
C/C++的书籍或者标准中,都没有规定调用约定。
还是说,这些只是事实上的标准?
 
如果只是事实上的标准,这些规律的应用范围只限于x86以及其兼容机?


// plantform.hpp
typedef char      int8_t;
// 应该是这样
typedef signed char int8_t;



char可能是signed,也可能是unsigned,由实现决定。

甚至,char、signed char、unsigned char都是3种不同的类型(无论char是signed还是unsigned)。

char这里比较特殊……

QueryPerformanceCounter(reinterpret_cast<LARGE_INTEGER*>(&mT1));
 
对这个cast, 可以考虑这么去掉:
 
LARGE_INTEGER temp = LARGE_INTEGER();
QueryPerformanceCounter(
&temp);
mT1 
= temp.QuadPart;
关于高精度数 我有过很多想法 …… 有空讨论 ……
stdint嘛 …… boost里面有。。。
google 搜搜 也有下载的地方。。。
你有MinGW就最方便了,直接从MinGW\include下复制就好了
stdint.h inttypes.h
都有

没必要自己写吧。。。
re: 复杂结构体的存取器 OwnWaterloo 2009-02-21 20:07
@Anonymous
阁下有何高见? 还是说,只有说屁话的本事?
re: 如何关闭Visual Studio 2008 OwnWaterloo 2009-02-20 16:43
试试先用文件菜单里的“关闭解决方案”,等解决方案关掉之后,再关闭VS。
re: 消息映射机制的简单实现 OwnWaterloo 2009-02-19 23:23
@cppexplore
我觉得加QQ聊会快一点…… “六久久思武柳留灵”

不是同一套,那么A向B发一个65以上的消息,B如何知道代表什么含义呢?
要么:A只向B发64以下的消息。
要么:存在T1,T2, ... Tn个线程,每个线程下分别有
A11,A12, ... An1...
A21,A22, ... An2...
...
A[i][j]只会和A[i][k]直接交互
A[i][j]和A[k][l]通过某种机制间接交互



-----------------------------
【貌似你一直谈的是后续。 】
可能是这样的,我在
http://www.cppblog.com/Fox/archive/2008/09/29/63056.aspx#74178
也说了。

re: 消息映射机制的简单实现 OwnWaterloo 2009-02-19 22:42
@cppexplore

第1个疑问:
系统中所有类使用的消息代码是否是同一套?都是
enum MsgType
{
MSG_TYPE_1=65,//64一下预留,用于统一的管理控制
MSG_TYPE_2,
..
MSG_TYPE_MAX
};
???

第2个疑问:(同时也是回答)
确实如你所说,我是【纸上谈兵】。
我没有【大型程序】的开发经验,更是不能理解:
【大型程序开发中,使用虚函数方式,文件个数膨胀的问题。】
这是为什么? 请指教~~~ 昨天就想问你了,字打多了就忘了……

re: 消息映射机制的简单实现 OwnWaterloo 2009-02-19 02:16
移植性确实会在不支持虚函数的语言中完败。
论理解、扩展、维护、简单的话,你现在仍然觉得虚函数比不上表格吗?
re: 消息映射机制的简单实现 OwnWaterloo 2009-02-19 02:16
                              考虑扩展
 
添加一个新的消息处理类。
如果基类不是纯虚函数,那最简单了,覆写需要关心的消息就可以了。
如果是纯虚函数,需要实现所有消息处理函数,对不关心的消息,使用基类默认处理。
 
而你的方案,不得不将所有的消息都映射一遍——因为【消息类型做数组下标,直接定位取处理函数】——即使不关心而作一个空函数。 
BEGIN_MESSAGE_MAP(SessionManager,SessionMsg)
    ON_MESSAGE(MSG_TYPE_1, SessionManager::do_msg_type_1_)
    ON_MESSAGE(MSG_TYPE_2, SessionManager::do_msg_type_2_)
    
// .. MORE
END_MESSAGE_MAP()
如果不是这样,请务必告诉我你是怎么不使用虚函数实现的。
 
 
添加一个新的消息种类(消息代码)
如果可以保证消息代码连续,可以使用上面的方案2,在表格中多加入一条。
如果不能保证消息代码连续(并且非常稀疏),就只能采用swtich case。
 
已经编写好的具体的消息处理类,如果都可以安全忽略该消息,那么可以采用上面的方案2——基类有默认实现且不纯虚——那么除了基类,已经编写好的具体类都不需要修改
如果不全都可以安全忽略该消息,那么可以采用上面的方案1——基类有空实现,但是纯虚——具类中可以忽略该消息的,使用基类实现,不能忽略的,编写处理函数。
 
而你的方案,一旦添加一个新的消息处理代码(同时要保证连续),所有的消息处理类都必须在其表格中增加一项。
re: 消息映射机制的简单实现 OwnWaterloo 2009-02-19 01:57
@cppexplore
【怎么不直接去我blog回复呢 呵呵】
好像是cppblog对url的分析有点问题,这个url: http://www.cppblog.com/CppExplore/archive/2008/11/07/66216.html
会被截取,只将前面一部分(也就是你的主页)制作成链接,点过去没看见什么文章……
后来才发现这个问题,找到那篇文章……
【容易理解,容易扩展,容易维护,容易移植,容易简单化】
嗯,这是重点。同时我也赞同你文章里最后一句话【一句话:重要的是思想,不是平台和语言。】
 
"你的实现就是模拟C++虚函数的经典实现",这个观点你赞同吗?
你的系统需要考虑向C(以及不支持虚函数的语言)移植吗?
 
如果赞同且不需要,那么继续讨论理解扩展维护简单
你的系统具体要做什么不太了解,我用win32作例子可以吗?比如,现在需要关心的消息只有2个:
enum MsgType {
    WM__LBUTTONDOWN 
/*= 0*/,
    WM__SIZING,
    
// 
};
struct Msg {
    MsgType type;
    HWND    hwnd;
    WPARAM  wparam;
    LPARAM  lparam;
};

如果使用C++虚函数机制:
 
class IHandler {
public:
    
virtual ~IHandler() {};
protected:
    
virtual void OnLButtonDown(POINTS pt,bool ctrl,bool shift,bool l,bool m,bool r) = 0 {};
    
virtual void OnSizing(RECT& rc,int side) = 0 {};
public:
    LRESULT Do(Msg
* msg) {
        
switch (msg->type) {
            
case WM__LBUTTONDOWN:
                OnLButtonDown(MAKEPOINTS(msg
->lparam)
                             ,msg
->wparam & MK_CONTROL
                             ,msg
->wparam & MK_SHIFT
                             ,msg
->wparam & MK_LBUTTON
                             ,msg
->wparam & MK_MBUTTON
                             ,msg
->wparam & MK_RBUTTON);
                
return 0;
            
case WM__SIZING:
                OnSizing(
*reinterpret_cast<RECT*>(msg->lparam),msg->wparam);
                
return 0;
        }

        
return DefWindowProc(msg->hwnd,msg->type,msg->wparam,msg->lparam);
    }

}
;
 
具体的消息处理类可以这样:
class Handler1 : public IHandler {
    
void OnLButtonDown(POINTS pt,bool ctrl,bool shift,bool l,bool m,bool r) {
        IHandler::OnLButtonDown(pt,ctrl,shift,l,m,r);
    }

    
void OnSizing(RECT& rc,int side) {
        IHandler::OnSizing(rc,side);
    }

}
;
 
上面的基类的虚函数带有默认实现,但设置为纯虚函数。
具体类必须实现每个消息处理过程,如果不关心,可以简单使用基类实现。
另一种方式:基类提供默认实现,并且不是纯虚函数;具体类只需覆写关心的消息。
 
另一方面,上面的基类没有使用表格,如果觉得switch case 不好维护,也可以使用表格。
 
两方面都采用另一种方案的话,基类就如下:
class IHandler {
public:
    
virtual ~IHandler() {};
private:
    
virtual void OnLButtonDown(POINTS pt,bool ctrl,bool shift,bool l,bool m,bool r)  {};
    
virtual void OnSizing(RECT& rc,int side)  {};
public:
    LRESULT Do(Msg
* msg) {
        assert(msg
->type>=0 && msg->type<WM__SIZING);
        
return MsgProcs[msg->type](msg->hwnd,msg->type,msg->wparam,msg->lparam,this);
    }


private:
    typedef LRESULT (
*MsgProc)(HWND,MsgType,WPARAM,LPARAM,IHandler* handler);
    
const static MsgProc MsgProcs[];
    
static LRESULT OnLButtonDown(HWND,MsgType,WPARAM wparam,LPARAM lparam,IHandler* handler) {
        handler
->OnLButtonDown(MAKEPOINTS(lparam)
                              ,wparam 
& MK_CONTROL
                              ,wparam 
& MK_SHIFT
                              ,wparam 
& MK_LBUTTON
                              ,wparam 
& MK_MBUTTON
                              ,wparam 
& MK_RBUTTON);
        
return 0;
    }

    
static LRESULT OnSizing(HWND,MsgType,WPARAM wparam,LPARAM lparam,IHandler* handler) {
        handler
->OnSizing(*reinterpret_cast<RECT*>(lparam),wparam);
        
return 0;
    }

}
;

const IHandler::MsgProc IHandler::MsgProcs[] = {
    IHandler::OnLButtonDown,
    IHandler::OnSizing,
}
;

具体类的编写就更简单: 假设仅关心OnLButtonDown
class Handler1 : public IHandler {
    
void OnLButtonDown(POINTS pt,bool ctrl,bool shift,bool l,bool m,bool r) {
        printf(
"(%d,%d) ctrl=%d,shitf=%d\n",pt.x,pt.y,ctrl,shift);
    }

}
;

 

re: 消息映射机制的简单实现 OwnWaterloo 2009-02-18 18:03
@cppexplore

再看了下你的实现,好像我们讨论的着重点不一样。

1. 你的系统里,是不是首先有这样一个需求:
因为某种原因(分布式,进程间,无锁线程),消息的发送者不能直接调用消息处理函数,而是传送一个消息代码来表示需要处理的类型?

消息代码即是win32中的WM_XX或者你的系统中的 enum MsgType { MSG_TYPE_1=65, ...  };



2. 消息的处理者,又需要按照约定(即消息代码的含义),将其映射到某个处理函数中。

如 win32 中
switch (message) {
case WM_XXX:
   return OnXXX(hwnd,message,wparam,lparam);
...
}

或者你的系统中的
switch(msg->type)
{
    
case MSG_TYPE_1:
         do_msg_type_1_();
         
break;
    
case MSG_TYPE_2:
         do_msg_type_2_();
         
break;
    ..
    
default:
             do_default_msg_();
             
break;
}



在这一步,确实是你的实现方式时间效率比较高。
但是在win32中, 这样做不太现实 ……  1000多个消息,表格就要包含1000多项,而且大多都是DefWndProc。

并且,在这一步中,虚函数根本就提供不了任何帮助
你的着重点在这一步?


3. 你想实现一个消息处理者B,它对大多数消息的处理方式同A一样,这时候如何尽可能的使用A的实现?
(暂不说依赖于某实现是不太恰当的设计,在MFC中多如牛毛……)

我的着重点在这里,我对处理这步的观点是: 『消息类型做数组下标了,直接定位取处理函数』与『覆写虚函数』相比,时空效率是相同的,我觉得后者更容易理解和扩展。


re: 消息映射机制的简单实现 OwnWaterloo 2009-02-18 16:40
@cppexplore

【查表是本质】
这句你说到重点了,虚函数和你实现的那个还有哪些所谓的用C实现OO的,都是查表。

【为什么要使用虚函数?更容易理解?MFC的消息映射展现方式很难理解吗? 虚函数更容易扩展吗?】
你这个实现就是在『模拟』虚函数。

上面的时空分析,可以量化,我有把握你会同意我的观点——两者时空效率完全一样——这个扩展性嘛,不容易量化 ……

你可以试着把你的实现用虚函数改写一下(再次说明,时空效率完全一样)。看看是否觉得虚函数更容易理解,更容易扩展。



btw:推荐你看看这个,MFC会什么会采用消息映射而不是虚函数的理由,《C++多态技术的实现和反思》
http://dev.yesky.com/189/2385189.shtml

re: 消息映射机制的简单实现 OwnWaterloo 2009-02-18 16:29
@cppexplore

1. 时间消耗

时间消耗自然不用说,是你的实现最得意的部分,o(1)。
同样,虚函数也是o(1)。

2. 空间消耗

假设你总共有N个消息,你仔细看看你的实现:
是不是每个(要处理消息的)类有一个长度会N的函数表,
空间大小至少是N×sizeof(void*);
每个对象有一个指向(或间接指向)该表的指针,
空间大小至少是sizeof(void*)。

虚函数的经典实现的空间消耗也是one class one vtbl, one object one vptr,和你的实现还是相同的。


这就回答了你一个问题:
【我不能认同,这个因素在整个系统中的开销你有没有量化过?比如 因为采用它导致并发数下降了多少多少之类?】
两者的时间空间效率是完全一致的,即使我没有量化过,也可以肯定,不会导致并发数下降。



re: 消息映射机制的简单实现 OwnWaterloo 2009-02-18 02:35
@cppexplore
我再说明白一点:
既然【用消息类型做数组下标,直接定位处理函数】,为什么不直接使用虚函数?

你的方案是为了消息路由而消息路由,没能理解采用消息路由的”苦衷“——如果采用更容易理解的虚函数来实现,虚表将占用比较多的资源,不得已而采用消息路由。
re: 消息映射机制的简单实现 OwnWaterloo 2009-02-18 02:30
@cppexplore
【消息类型做数组下标了,直接定位取处理函数,这都是无关紧要的细节。】
这恰恰是最重要的细节 …… 这样做得不偿失……



re: 从Win32 API封装Thread类[1] OwnWaterloo 2008-10-10 01:36
我有2个建议, 一个可以慎重考虑一下, 另外一个可以完全不理睬。
还有2个疑问 ……

1.单下划线开始的标识符?

2.将windows.h 从thread.h中移走
.h
class Thread {
//
private:
uintptr_t handle_;
}

.cpp
handle_ = _beginthreadex 这个可以直接赋值
CloseHandle( reinterpret_cast<HANDLE>( handle_ ); 这个要自己转
虽然麻烦一点, 但是将 windows.h 隔离到了头文件之外




疑问:
1. Thread的析构

10 Thread::~Thread() {
11 if (_handle != 0)
12 CloseHandle(_handle);
13 if (_target != 0)
14 delete _target;
15 }

CloseHandle 线程并不停止
如果主线程没有join delete _target; 后 线程还在run

这是线程函数
34 unsigned __stdcall Thread::threadProc(void *param) {
35 Thread *p = static_cast<Thread*>(param);
36 if (p->_target != 0)
37 p->_target->run();
38 else
39 p->run();
40 return 0;
41 }

37 行, 如果被delete, 而且run访问了数据, 而不仅仅是打印一些console消息, 肯定会引发错误。


疑问是: join 是惯例? 规范? 还是仅仅是boost的示例而已。


2.Thread 似乎并不需要从 Runable 继承。
完全可以设计成 Thread是Runable的容器。

疑问是: 仅仅是为了模仿Java的行为?
re: 从Win32 API封装Thread类[1] OwnWaterloo 2008-10-10 01:23
@Robinfoxnan
我帮楼主回你了 ~~

侯捷的书, 肯定说的是不要使用 CreateTread 这个API
如果他说的是不要使用 _beginthreadex , 那他该被拖出去打。

至于AfxBeginThread ,windows平台下写程序一定要和MFC扯上关系么?

既然你提到了AfxBeginThread, 你可以去看一下MFC的源码, MFC80, 它就是使用的 _beginthreadex ~~

共10页: First 2 3 4 5 6 7 8 9 10 
<2024年3月>
252627282912
3456789
10111213141516
17181920212223
24252627282930
31123456

常用链接

留言簿(8)

随笔档案(16)

链接

搜索

  •  

积分与排名

  • 积分 - 194752
  • 排名 - 132

最新随笔

最新评论

阅读排行榜

评论排行榜