我们的工程马上就要发布,但是在一个干净的,即没有安装vs2005的xp上运行(利用虚拟机测试)却弹出下面得错误
“由于应用程序配置不正确,应用程序未能启动。重新安装应用程序可能会纠正这个问题“
在英文os上:
This application has failed to start because the application configuration is incorrect. Reinstalling the application may fix this problem.
考虑到程序的运行环境问题,可能是由于没有安装.netFrameWork.但是后来安装上之后仍然如故。郁闷。。。
在网上找出了这些方法:
方法一:
在类似C:\Program Files\Microsoft Visual Studio 8\VC\redi
st\Debug_NonRedist\x86\Microsoft.VC80.DebugCRT 下找到了下列文件:
msvcm80d.dll
msvcp80d.dll
msvcr80d.dll
Microsoft.VC80.DebugCRT.manifest
把这几个文件拷贝到目标机器上,与运行程序同一文件夹或放到system32下,就可以正确运行了。
其他release版、MFC程序什么的都是拷redist下相应文件夹下的文件就可以了,文件夹后都有标识!
方法二:
修改编译选项,将/MD或/MDd 改为 /MT或/MTd,这样就实现了对VC运行时库的静态链接,在运行时就不再需要VC的dll了。
注:MSDN中对于在不同的配置下Link的LIB作了说明:
C Runtime Library:
开关 对应的库 版本
/MD MSVCRT.LIB 多线程DLL的Release版本
/MDd MSVCRTD.LIB 多线程DLL的Debug版本
/MT LIBCMT.LIB 多线程静态链接的Release版本
/MTd LIBCMTD.LIB 多线程静态链接的Debug版本
/clr MSVCMRT.LIB 托管代码和非托管代码混合
/clr:pure MSVCURT.LIB 纯托管代码 
C++ Standard Library:
开关 对应的库 版本
/MD MSVCPRT.LIB 多线程DLL的Release版本
/MDd MSVCPRTD.LIB 多线程DLL的Debug版本
/MT LIBCPMT.LIB 多线程静态链接的Release版本
/MTd LIBCPMTD.LIB 多线程静态链接的Debug版本 
编译器会自动根据编译选项,选择对应的LIB文件。一般情况下这不会出现问题。
然而,在部分情况下,一旦你的程序的各个部分(LIB, OBJ…)并非由相同的编译选项编译出,而Link在一起的话,会出现各种各样的看似很难解决的问题,这类问题主要以重复定义的错误形式存在,通常的解决方法也很简单,就是选择同样的编译选项进行编译之后再Link
方法三:
工程-》属性-》配置属性-》常规-》MFC的使用,选择“在静态库中使用mfc”
这样生成的exe文件应该就可以在其他机器上跑了。
方法四:
安装vcredist_x86.exe

这样四步下来,大部分程序都应该可以运行了,但悲哀的是在我的测试机上还是报应用程序配置错误。无奈。。
后打开vs2005的命令行,运行depends.exe,试图找出程序启动所依赖的dll,结果大失所望,虚拟机上这些dll都有。如此这般令人抓狂。
最后把vs2005安装目录下的所有.manifest文件(可以搜索 *.manifest得到)都考到程序目录下,程序奇迹般的可以运行。
然后实验,删掉冗余的.manifest文件,只需要5个就够了。它们是Microsoft.VC80.ATL.manifest
Microsoft.VC80.CRT.manifest
Microsoft.VC80.DebugCRT.manifest
Microsoft.VC80.DebugMFC.manifest
Microsoft.VC80.MFC.manifest

posted @ 2009-11-10 13:58 micheal's tech 阅读(858) | 评论 (0)编辑 收藏

方法1:过该点作一条射线,然后判断该射线与三条边的相交情况;  
  方法2:分别连接P点和三个顶点A,B,C,然后判断矢量PA,PB,PC所夹角之和是否为360度,如果是360度则P在三角形内  
   
  1.    
  #include   <stdio.h>  
  #include   <math.h>  
   
  struct   TPoint  
  {  
  float   x;  
  float   y;  
  };  
   
  float   area(struct   TPoint   p1,struct   TPoint   p2,struct   TPoint   p3){  
  return   fabs((p1.x-p3.x)*(p2.y-p3.y)-(p2.x-p3.x)*(p1.y-p3.y));  
  }  
   
  float   mul(struct   TPoint   p1,struct   TPoint   p2,struct   TPoint   p0){  
  return((p1.x-p0.x)*(p2.y-p0.y)-(p2.x-p0.x)*(p1.y-p0.y));  
  }  
   
  int   inside(struct   TPoint   tr[],struct   TPoint   p){  
  int   i;  
  for   (i=0;i<3;i++)  
  if   (mul(p,tr[i],tr[(i+1)%3])*mul(p,tr[(i+2)%3],tr[(i+1)%3])>0)  
  return   0;  
  return   1;  
  }  
   
  int   inside2(struct   TPoint   tr[],struct   TPoint   p){  
  if   (fabs(area(tr[0],tr[1],tr[2])-  
    area(p,tr[1],tr[2])-  
    area(tr[0],p,tr[2])-  
    area(tr[0],tr[1],p))<1.0e-20)  
  return   1;  
  else  
  return   0;  
  }  
   
  main(){  
  struct   TPoint   tr[3]={{-1,1},{1,0},{3,0}},p={1,2};  
  printf("algorithm   1:");  
  if   (inside(tr,p))  
  printf("In\n");  
  else  
  printf("Out\n");  
  printf("algorithm   2:");  
  if   (inside2(tr,p))  
  printf("In\n");  
  else  
  printf("Out\n");  
  }  
   
  2  
  就是判断点到三个顶点的夹角之和为2*PI  
  //   返回1   表示在那,0表示在外  
  int   inside3(const   struct   TPoint   tr[],   struct   TPoint   p)  
  {  
  TPoint   p0,p1,p2;  
  p0.x   =   tr[0].x   -   p.x   ;     p0.y   =   tr[0].y   -   p.y;  
  p1.x   =   tr[1].x   -   p.x   ;     p1.y   =   tr[1].y   -   p.y;  
  p2.x   =   tr[2].x   -   p.x   ;     p2.y   =   tr[2].y   -   p.y;  
   
  double   arg1   =   acos((p0.x*p1.x   +   p0.y*p1.y)/sqrt(p0.x*p0.x   +   p0.y*p0.y)/sqrt(p1.x*p1.x+p1.y*p1.y));  
  double   arg2   =   acos((p0.x*p2.x   +   p0.y*p2.y)/sqrt(p0.x*p0.x   +   p0.y*p0.y)/sqrt(p2.x*p2.x+p2.y*p2.y));  
  double   arg3   =   acos((p2.x*p1.x   +   p2.y*p1.y)/sqrt(p2.x*p2.x   +   p2.y*p2.y)/sqrt(p1.x*p1.x+p1.y*p1.y));  
   
  if(   fabs(2*3.1415926-arg1-arg2-arg3)<0.0001   )   return   1;  
  return   0;  
  }  
   

posted @ 2009-11-04 21:07 micheal's tech 阅读(1819) | 评论 (0)编辑 收藏

directhsow filter 里不能用std::vector


You've got a very odd mix of managed and unmanaged code.  You're definitely missing msvcprtd.lib.  That should knock a good chunk of those errors out.  Project templates are almost always a good idea.

posted @ 2009-11-04 16:18 micheal's tech 阅读(169) | 评论 (0)编辑 收藏

    今天dot.kde登了一篇对valgrind的作者 访谈。我作为valgrind的老用户,当年调程序时获益很多,在这篇访谈里进一步长了见识,深感有必要把这个优秀的开发工具介绍给诸位。以下内容多翻译自该访谈(意译啦)。

啥是valgrind

    Valgrind是帮助程序员寻找程序里的bug和改进程序性能的工具。程序通过valgrind运行时,valgrind收集各种有用的信息,通过这些信息可以找到程序中潜在的bug和性能瓶颈。
    Valgrind现在提供多个工具,其中最重要的是Memcheck,Cachegrind,Massif和Callgrind。

Memcheck:

    这个工具可以用来寻找c、c++和fortran程序中内存管理的错误。写c或c++程序时,很多隐藏很深的bug是内存操作上出了问题。而这些在 Memcheck面前都无处遁形(偶当年用的就是这个功能)。Memcheck可以检查出下列几种内存操作上的错误(大家自查一下有没有犯过;):
  • 读写已经释放的内存
  • 读写内存块越界(从前或者从后)
  • 使用还未初始化的变量
  • 将无意义的参数传递给系统调用
  • 内存泄漏
  • (笔者补充一条,同一个malloc的内存块释放多次。当年这么个bug让我找翻天)      

Cachegrind:

    这个工具可以提供详尽的profiling信息。它不光对指令、内存访问进行计数,更能针对每条指令、每行源代码、每个函数和每个程序统计cache的不 命中次数。大家应该知道,cache对目前系统的性能有决定性的影响。因此这些信息可以指导程序员调整代码,最大限度的提高程序性能。
    访谈中提到,valgrind自身利用该工具在过去几个月内使性能提高了25%-30%。据早先报道,kde的开发team也对valgrind在提高kde性能方面的帮助表示感谢。

Massif:

    Massif对内存的分配和释放做profile。程序开发者通过它可以深入了解程序的内存使用行为,从而对内存使用进行优化。这个功能对C++尤其有用(因为C++有很多隐藏的内存分配和释放)。

Callgrind:

    Callgrind是一个复杂的工具(复杂到笔者没看太明白有关它的介绍)。它基于Cachegrind,除了具有Cachegrind的功能外,还可以统计调用带来的开销。

用法:

    Valgrind使用起来非常简单,你甚至不需要重新编译你的程序就可以用它。当然如果要达到最好的效果,获得最准确的信息,还是需要按要求重新编译一下的。比如在使用memcheck的时候,最好关闭优化选项。

posted @ 2009-02-02 16:50 micheal's tech 阅读(770) | 评论 (0)编辑 收藏

【转】一个简单的线程池(c++版)

#ifndef _ThreadPool_H_
#define _ThreadPool_H_
#pragma warning(disable: 4530)
#pragma warning(disable: 4786)
#include <cassert>
#include <vector>
#include <queue>
#include <windows.h>
class ThreadJob  //工作基类
{
public:
    //供线程池调用的虚函数
    virtual void DoJob(void *pPara) = 0;
};
class ThreadPool
{
public:
    //dwNum 线程池规模
    ThreadPool(DWORD dwNum = 4) : _lThreadNum(0), _lRunningNum(0)
    {
        InitializeCriticalSection(&_csThreadVector);
        InitializeCriticalSection(&_csWorkQueue);
        _EventComplete = CreateEvent(0, false, false, NULL);
        _EventEnd = CreateEvent(0, true, false, NULL);
        _SemaphoreCall = CreateSemaphore(0, 0,  0x7FFFFFFF, NULL);
        _SemaphoreDel =  CreateSemaphore(0, 0,  0x7FFFFFFF, NULL);
        assert(_SemaphoreCall != INVALID_HANDLE_VALUE);
        assert(_EventComplete != INVALID_HANDLE_VALUE);
        assert(_EventEnd != INVALID_HANDLE_VALUE);
        assert(_SemaphoreDel != INVALID_HANDLE_VALUE);
        AdjustSize(dwNum <= 0 ? 4 : dwNum);
    }
    ~ThreadPool()
    {
        DeleteCriticalSection(&_csWorkQueue);
        CloseHandle(_EventEnd);
        CloseHandle(_EventComplete);
        CloseHandle(_SemaphoreCall);
        CloseHandle(_SemaphoreDel);
        vector<ThreadItem*>::iterator iter;
        for(iter = _ThreadVector.begin(); iter != _ThreadVector.end(); iter++)
        {
            if(*iter)
                delete *iter;
        }
        DeleteCriticalSection(&_csThreadVector);
    }
    //调整线程池规模
    int AdjustSize(int iNum)
    {
        if(iNum > 0)
        {
            ThreadItem *pNew;
            EnterCriticalSection(&_csThreadVector);
            for(int _i=0; _i<iNum; _i++)
            {
                _ThreadVector.push_back(pNew = new ThreadItem(this));
                assert(pNew);
                pNew->_Handle = CreateThread(NULL, 0, DefaultJobProc, pNew, 0, NULL);
                assert(pNew->_Handle);
            }
            LeaveCriticalSection(&_csThreadVector);
        }
        else
        {
            iNum *= -1;
            ReleaseSemaphore(_SemaphoreDel,  iNum > _lThreadNum ? _lThreadNum : iNum, NULL);
        }
        return (int)_lThreadNum;
    }
    //调用线程池
    void Call(void (*pFunc)(void  *), void *pPara = NULL)
    {
        assert(pFunc);
        EnterCriticalSection(&_csWorkQueue);
        _JobQueue.push(new JobItem(pFunc, pPara));
        LeaveCriticalSection(&_csWorkQueue);
        ReleaseSemaphore(_SemaphoreCall, 1, NULL);
    }
    //调用线程池
    inline void Call(ThreadJob * p, void *pPara = NULL)
    {
        Call(CallProc, new CallProcPara(p, pPara));
    }
    //结束线程池, 并同步等待
    bool EndAndWait(DWORD dwWaitTime = INFINITE)
    {
        SetEvent(_EventEnd);
        return WaitForSingleObject(_EventComplete, dwWaitTime) == WAIT_OBJECT_0;
    }
    //结束线程池
    inline void End()
    {
        SetEvent(_EventEnd);
    }
    inline DWORD Size()
    {
        return (DWORD)_lThreadNum;
    }
    inline DWORD GetRunningSize()
    {
        return (DWORD)_lRunningNum;
    }
    bool IsRunning()
    {
        return _lRunningNum > 0;
    }
protected:
    //工作线程
    static DWORD WINAPI DefaultJobProc(LPVOID lpParameter = NULL)
    {
        ThreadItem *pThread = static_cast<ThreadItem*>(lpParameter);
        assert(pThread);
        ThreadPool *pThreadPoolObj = pThread->_pThis;
        assert(pThreadPoolObj);
        InterlockedIncrement(&pThreadPoolObj->_lThreadNum);
        HANDLE hWaitHandle[3];
        hWaitHandle[0] = pThreadPoolObj->_SemaphoreCall;
        hWaitHandle[1] = pThreadPoolObj->_SemaphoreDel;
        hWaitHandle[2] = pThreadPoolObj->_EventEnd;
        JobItem *pJob;
        bool fHasJob;
        for(;;)
        {
            DWORD wr = WaitForMultipleObjects(3, hWaitHandle, false, INFINITE);
            //响应删除线程信号
            if(wr == WAIT_OBJECT_0 + 1) 
                break;
            //从队列里取得用户作业
            EnterCriticalSection(&pThreadPoolObj->_csWorkQueue);
            if(fHasJob = !pThreadPoolObj->_JobQueue.empty())
            {
                pJob = pThreadPoolObj->_JobQueue.front();
                pThreadPoolObj->_JobQueue.pop();
                assert(pJob);
            }
            LeaveCriticalSection(&pThreadPoolObj->_csWorkQueue);
            //受到结束线程信号确定是否结束线程(结束线程信号&& 是否还有工作)
            if(wr == WAIT_OBJECT_0 + 2 && !fHasJob) 
                break;
            if(fHasJob && pJob)
            {
                InterlockedIncrement(&pThreadPoolObj->_lRunningNum);
                pThread->_dwLastBeginTime = GetTickCount();
                pThread->_dwCount++;
                pThread->_fIsRunning = true;
                pJob->_pFunc(pJob->_pPara); //运行用户作业
                delete pJob;
                pThread->_fIsRunning = false;
                InterlockedDecrement(&pThreadPoolObj->_lRunningNum);
            }
        }
        //删除自身结构
        EnterCriticalSection(&pThreadPoolObj->_csThreadVector);
    pThreadPoolObj->_ThreadVector.erase(find(pThreadPoolObj->_ThreadVector.begin(), pThreadPoolObj->_ThreadVector.end(), pThread));
        LeaveCriticalSection(&pThreadPoolObj->_csThreadVector);
        delete pThread;
        InterlockedDecrement(&pThreadPoolObj->_lThreadNum);
        if(!pThreadPoolObj->_lThreadNum)  //所有线程结束
            SetEvent(pThreadPoolObj->_EventComplete);
        return 0;
    }
    //调用用户对象虚函数
    static void CallProc(void *pPara)
    {
        CallProcPara *cp = static_cast<CallProcPara *>(pPara);
        assert(cp);
        if(cp)
        {
            cp->_pObj->DoJob(cp->_pPara);
            delete cp;
        }
    }
    //用户对象结构
    struct CallProcPara 
    {
        ThreadJob* _pObj;//用户对象
        void *_pPara;//用户参数
        CallProcPara(ThreadJob* p, void *pPara) : _pObj(p), _pPara(pPara) { };
    };
    //用户函数结构
    struct JobItem
    {
        void (*_pFunc)(void  *);//函数
        void *_pPara; //参数
        JobItem(void (*pFunc)(void  *) = NULL, void *pPara = NULL) : _pFunc(pFunc), _pPara(pPara) { };
    };
    //线程池中的线程结构
    struct ThreadItem
    {
        HANDLE _Handle; //线程句柄
        ThreadPool *_pThis;  //线程池的指针
        DWORD _dwLastBeginTime; //最后一次运行开始时间
        DWORD _dwCount; //运行次数
        bool _fIsRunning;
        ThreadItem(ThreadPool *pthis) : _pThis(pthis), _Handle(NULL), _dwLastBeginTime(0), _dwCount(0), _fIsRunning(false) { };
        ~ThreadItem()
        {
            if(_Handle)
            {
                CloseHandle(_Handle);
                _Handle = NULL;
            }
        }
    };
    std::queue<JobItem *> _JobQueue;  //工作队列
    std::vector<ThreadItem *>  _ThreadVector; //线程数据
    CRITICAL_SECTION _csThreadVector, _csWorkQueue; //工作队列临界, 线程数据临界
    HANDLE _EventEnd, _EventComplete, _SemaphoreCall, _SemaphoreDel;//结束通知, 完成事件, 工作信号,删除线程信号
    long _lThreadNum, _lRunningNum; //线程数, 运行的线程数
};
#endif //_ThreadPool_H_

使用说明1:

调用方法

void threadfunc(void *p)
{
     YourClass* yourObject = (YourClass*)    p;
 //
}
 ThreadPool tp;
 for(i=0; i<100; i++)
  tp.Call(threadfunc);
ThreadPool tp(20);//20为初始线程池规模
 tp.Call(threadfunc, lpPara);

使用时注意几点:

1. ThreadJob  没什么用,直接写线程函数吧。 

2. 线程函数(threadfunc)的入口参数void* 可以转成自定义的类型对象,这个对象可以记录下线程运行中的数据,并设置线程当前状态,以此与线程进行交互。

3. 线程池有一个EndAndWait函数,用于让线程池中所有计算正常结束。有时线程池中的一个线程可能要运行很长时间,怎么办?可以通过线程函数threadfunc的入口参数对象来处理,比如:

class YourClass 
{
  int cmd; // cmd = 1是上线程停止计算,正常退出。
};
threadfunc(void* p) {
  YourClass* yourObject = (YourClass*)p;
  while (true) {
    // do some calculation
    if (yourClass->cmd == 1)
      break;
  }
}

在主线程中设置yourClass->cmd = 1,该线程就会自然结束。

使用说明2:

Code
void threadfunc(void *p)
{
 //
}
 ThreadPool tp;
 for(i=0; i<100; i++)
  tp.Call(threadfunc);
 ThreadPool tp(20);//20为初始线程池规模
 tp.Call(threadfunc, lpPara);
 tp.AdjustSize(50);//增加50
 tp.AdjustSize(-30);//减少30

 

class MyThreadJob : public ThreadJob //线程对象从ThreadJob扩展
{
public:
 virtual void DoJob(void *p)//自定义的虚函数
 {
  //.
 }
};
 MyThreadJob mt[10];
 ThreadPool tp;
 for(i=0; i<100 i++)
  tp.Call(mt + i);//tp.Call(mt + i, para);

posted @ 2009-02-02 16:28 micheal's tech 阅读(6027) | 评论 (0)编辑 收藏

多线程同步机制摘要

Posted on 2007-04-03 19:34 kk 阅读(1306) 评论(0)  编辑 收藏 引用 所属分类: IT
  Critical Section

Critical section(临界区)用来实现“排他性占有”。适用范围是单一进程的各线程之间。它是:

·         一个局部性对象,不是一个核心对象。

·         快速而有效率。

·         不能够同时有一个以上的critical section被等待。

·         无法侦测是否已被某个线程放弃。

Mutex

Mutex是一个核心对象,可以在不同的线程之间实现“排他性占有”,甚至几十那些现成分属不同进程。它是:

·         一个核心对象。

·         如果拥有mutex的那个线程结束,则会产生一个“abandoned”错误信息。

·         可以使用Wait…()等待一个mutex。

·         可以具名,因此可以被其他进程开启。

·         只能被拥有它的那个线程释放(released)。

Semaphore

Semaphore被用来追踪有限的资源。它是:

·         一个核心对象。

·         没有拥有者。

·         可以具名,因此可以被其他进程开启。

·         可以被任何一个线程释放(released)。

Event Object

Event object通常使用于overlapped I/O,或用来设计某些自定义的同步对象。它是:

·         一个核心对象。

·         完全在程序掌控之下。

·         适用于设计新的同步对象。

·         “要求苏醒”的请求并不会被储存起来,可能会遗失掉。

·         可以具名,因此可以被其他进程开启。

Interlocked Variable

如果Interlocked…()函数被使用于所谓的spin-lock,那么他们只是一种同步机制。所谓spin-lock是一种busy loop,被预期在极短时间内执行,所以有最小的额外负担(overhead)。系统核心偶尔会使用他们。除此之外,interlocked variables主要用于引用技术。他们:

·         允许对4字节的数值有些基本的同步操作,不需动用到critical section或mutex之类。

·         在SMP(Symmetric Multi-Processors)操作系统中亦可有效运作。


posted @ 2009-02-02 14:35 micheal's tech 阅读(705) | 评论 (0)编辑 收藏

高性能服务器的多线程策略


(一)线程数量与线程池模型
  参见:high-performance server design. http://pl.atyp.us/content/tech/servers.html

  频繁的上下文切换,会导致系统性能严重下降,而产生过多的切换大致有两个原因:
1)过多的线程数量。这会使系统性能呈指数级的下降。对于每连接一个线程的系统而言,这也是为什么性能会变差的原因。一个具有可伸缩性的系统,它的唯一 可行的选择,就是限制运行线程的数量。一般而言,这个值应该小于或等于处理器的数目。(说明,在boost网络库asio提供的example中,有一个 关于这种实现的很好的例子)
  2)所使用的线程池及事件模型。最简单的一种模型通常是这个样子:一个侦听线程异步地接收请求,并在队列中进行缓 冲。另外一组工作者线程则负责处理这些请求。这是一个不错的模型,缺点就是每处理一个请求一般要经过两次线程切换(加上对请求的回复)。为了避免这种缺 点,一个线程就必须具备侦听者和工作者两种角色,可以采用称之谓“领导者/跟随者”的模型。一个线程作为领导者,来进行监听,当收到请求时,它选出一个跟 随者线程作为新的领导者进行侦听,自己则对请求进行处理,结束后,到跟随者队列中进行等待。

(二)多线程的内存池优化

普通的内存池一旦应用到多线程中,都面临着锁竞争的问题,在stlport所做的对于字符串性能的测试中,当使用两个线程时,它所使用的内存池 node_allocator性能已经出现明显的下降。所以对于多线程而言,一个线程一个内存池是一个很好的选择。要实现这种设计,面临的第一个问题,是 内存块的跨线程使用问题,即一个内存块,可能在A线程中申请,但可能在B线程中释放。
  在GCC的STL实现libstdc++中,有一个多线程内存池的实现(mt_allocator)。它是node_allocator(现在叫pool_allocator) 的多线程版本。它还有一个优点就是所有参数都是可配置的。
  它的设计思路如下:每个线程一个内存池,同时还有一个全局的内存池。每个线程可以访问自己的内存池,同时可在锁保护下访问全局内存池。申请的每一个内存块中,都有一个线程ID,以标明是从哪个线程中申请的。
  申请过程:首先向所在线程申请,若本线程没有空闲块,则向全局内存池申请。
  释放过程:直接归还到本线程的空闲链中。还有一个问题,为了防止线程内存池之间的不均衡,或者某一个线程中的空闲链过长,可以设置一个水位标,当超过这个水位标时,把释放的内存直接归还到全局内存池中。

posted @ 2009-01-12 16:38 micheal's tech 阅读(392) | 评论 (0)编辑 收藏


"placement new"? Embarrassed它 到底是什么东东呀?我也是最近几天才听说,看来对于C++我还差很远呀!placement new 是重载operator new的一个标准、全局的版本,它不能被自定义的版本代替(不像普通的operator new和operator delete能够被替换成用户自定义的版本)。

它的原型如下:
void *operator new( size_t, void *p ) throw()  { return p; }

首先我们区分下几个容易混淆的关键词:new、operator new、placement new
new和delete操作符我们应该都用过,它们是对中的内存进行申请和释放,而这两个都是不能被重载的。要实现不同的内存分配行为,需要重载operator new,而不是new和delete。I dont know

看如下代码:
class MyClass {…};
MyClass * p=new MyClass;

这里的new实际上是执行如下3个过程:


1. 调用operator new分配内存 ;2. 调用构造函数生成类对象;3. 返回相应指针。

operator new就像operator+一样,是可以重载的,但是不能在全局对原型为void operator new(size_t size)这个原型进行重载,一般只能在类中进行重载。如果类中没有重载operator new,那么调用的就是全局的::operator new来完成堆的分配。同理,operator new[]、operator delete、operator delete[]也是可以重载的,一般你重载的其中一个,那么最后把其余的三个都重载一遍。

至于placement new才是本文的重点。其实它也只是operator new的一个重载的版本,只是我们很少用到它。如果你想在已经分配的内存中创建一个对象,使用new时行不通的。也就是说placement new允许你在一个已经分配好的内存中(栈或者堆中)构造一个新的对象。原型中void*p实际上就是指向一个已经分配好的内存缓冲区的的首地址。

我们知道使用new操作符分配内存需要在堆中查找足够大的剩余空间,这个操作速度是很慢的,而且有可能出现无法分配内存的异常(空间不够)。 placement new就可以解决这个问题。我们构造对象都是在一个预先准备好了的内存缓冲区中进行,不需要查找内存,内存分配的时间是常数;而且不会出现在程序运行中途 出现内存不足的异常。所以,placement new非常适合那些对时间要求比较高,长时间运行不希望被打断的应用程序。

使用方法如下:
1. 缓冲区提前分配
可以使用堆的空间,也可以使用栈的空间,所以分配方式有如下两种:
class MyClass {…};
char *buf=new char[N*sizeof(MyClass)+ sizeof(int) ] ; 或者char buf[N*sizeof(MyClass)+ sizeof(int) ];

2. 对象的构造
MyClass * pClass=new(buf) MyClass;

3. 对象的销毁
一旦这个对象使用完毕,你必须显式的调用类的析构函数进行销毁对象。但此时内存空间不会被释放,以便其他的对象的构造。
pClass->~MyClass();

4. 内存的释放
如果缓冲区在堆中,那么调用delete[] buf;进行内存的释放;如果在栈中,那么在其作用域内有效,跳出作用域,内存自动释放。

注意:

  • 在C++标准中,对于placement operator new []有如下的说明: placement operator new[] needs implementation-defined amount of additional storage to save a size of array. 所以我们必须申请比原始对象大小多出sizeof(int)个字节来存放对象的个数,或者说数组的大小。
  • 使用方法第二步中的new才是placement new,其实是没有申请内存的,只是调用了构造函数,返回一个指向已经分配好的内存的一个指针,所以对象销毁的时候不需要调用delete释放空间,但必须调用析构函数销毁对象。

posted @ 2009-01-08 20:56 micheal's tech 阅读(1570) | 评论 (0)编辑 收藏

http://www.cppblog.com/dyj057/archive/2005/09/20/346.html

大家都知道,在用C++来实现Singleton模式的时候通常把构造函数声明为私有的或者保护的。同时声明一个公有的静态的伪构造函数,通过它来调用真正的构造函数。在实现这个伪构造函数的时候通常有两种方式:  
  class   Singleton;  
   
  static   Singleton&   Singleton:;fakeSingleton()  
  {  
          static   Singleton   s;  
          return   s;  
  }  
  第二种方式:  
  class   Singleton{  
  public:  
  static   Singleton*   fakeSingleton();  
  ...  
  private:  
  Singleton();  
  static   Singleton   *   _instance;  
  }  
  Singleton*   Singleton::fakesinketon()  
  {  
        if(   _instance==NULL)  
                  _instance=new   Singleton();  
          return   _instance;  
  }  
  对于这两种方式我觉得第一种更好一些,理由是,如果有两个以上的线程同时访问伪构造函数的时候有可能同时进入if   控制块,这样就有可能产生两个实例!!因此必须采用特殊的保护机制来控制同步。而第一种方式不存在这样的问题。  
   
  请高手指点!我不明白的是,为什么书上的例子还较多的采用第二种方法?莫非它有自己的优势??  
   

posted @ 2009-01-06 16:06 micheal's tech 阅读(1560) | 评论 (7)编辑 收藏

贪心法的基本思路:  
   
  从问题的某一个初始解出发逐步逼近给定的目标,以尽可能快的地求得更好的解。当达到某算法中的某一步不能再继续前进时,算法停止。  
  该算法存在问题:  
  1.   不能保证求得的最后解是最佳的;  
  2.   不能用来求最大或最小解问题;  
  3.   只能求满足某些约束条件的可行解的范围。 实现该算法的过程:  
  从问题的某一初始解出发;
  
  while   能朝给定总目标前进一步   do  
  求出可行解的一个解元素;  
  由所有解元素组合成问题的一个可行解

贪心算法最经典的例子,给钱问题。  
  比如中国的货币,只看元,有1元2元5元10元20、50、100  
   
  如果我要16元,可以拿16个1元,8个2元,但是怎么最少呢?  
  如果用贪心算,就是我每一次拿那张可能拿的最大的。  
  比如16,我第一次拿20拿不起,拿10元,OK,剩下6元,再拿个5元,剩下1元  
  也就是3张   10、5、1。  
   
  每次拿能拿的最大的,就是贪心。  
   
  但是一定注意,贪心得到的并不是最优解,也就是说用贪心不一定是拿的最少的张数  
  贪心只能得到一个比较好的解,而且贪心算法很好想得到。  
  再注意,为什么我们的钱可以用贪心呢?因为我们国家的钱的大小设计,正好可以使得贪心算法算出来的是最优解(一般是个国家的钱币都应该这么设计)。如果设计成别的样子情况就不同了  
  比如某国的钱币分为   1元3元4元  
  如果要拿6元钱   怎么拿?贪心的话   先拿4   再拿两个1     一共3张钱  
  实际最优呢?   两张3元就够了  


求最优解的问题,从根本上说是一种对解空间的遍历。最直接的暴力分析容易得到,最优解的解空间通常都是以指数阶增长,因此暴力穷举都是不可行的。
最优解问题大部分都可以拆分成一个个的子问题,把解空间的遍历视作对子问题树的遍历,则以某种形式对树整个的遍历一遍就可以求出最优解,如上面的分析,这是不可行的。
贪心和动态规划本质上是对子问题树的一种修剪。两种算法要求问题都具有的一个性质就是“子问题最优性”。即,组成最优解的每一个子问题的解,对 于这个子问题本身肯定也是最优的。如果以自顶向下的方向看问题树(原问题作根),则,我们每次只需要向下遍历代表最优解的子树就可以保证会得到整体的最优 解。形象一点说,可以简单的用一个值(最优值)代表整个子树,而不用去求出这个子树所可能代表的所有值。
动态规划方法代表了这一类问题的一般解法。我们自底向上(从叶子向根)构造子问题的解,对每一个子树的根,求出下面每一个叶子的值,并且以其中 的最优值作为自身的值,其它的值舍弃。动态规划的代价就取决于可选择的数目(树的叉数)和子问题的的数目(树的节点数,或者是树的高度?)。
贪心算法是动态规划方法的一个特例。贪心特在,可以证明,每一个子树的根的值不取决于下面叶子的值,而只取决于当前问题的状况。换句话说,不需 要知道一个节点所有子树的情况,就可以求出这个节点的值。通常这个值都是对于当前的问题情况下,显而易见的“最优”情况。因此用“贪心”来描述这个算法的 本质。由于贪心算法的这个特性,它对解空间树的遍历不需要自底向上,而只需要自根开始,选择最优的路,一直走到底就可以了。这样,与动态规划相比,它的代 价只取决于子问题的数目,而选择数目总为1。


posted @ 2008-11-18 11:20 micheal's tech 阅读(3505) | 评论 (0)编辑 收藏

仅列出标题
共8页: 1 2 3 4 5 6 7 8