colorful

zc qq:1337220912

 

why enable_shared_from_this

 为什么会有 tr1::enable_shared_from_this 这个类,一直不解,直到看了Stephan T. Lavavej给出的关于shared_ptr 的PPT。 Stephan T. Lavavej是Visual C++ Libraries Developer。

他给的例子是:

struct Ansible {
    shared_ptr<Ansible> get_shared() {
        shared_ptr<Ansible> ret(this);
        return ret;
    }
};

int main() {
    shared_ptr<Ansible> a(new Ansible);
    Ansible& r = *a;
    shared_ptr<Ansible> b = r.get_shared();
}

Result: DOUBLE DELETION


然后使用enable_shared_from_this 就对了:

struct Ansible
    : public enable_shared_from_this<Ansible> { };

int main() {
    shared_ptr<Ansible> a(new Ansible);
    Ansible& r = *a;
    shared_ptr<Ansible> b = r.shared_from_this();
}

a and b share ownership, as if:
shared_ptr<Ansible> b = a;



为什么?看看enable_shared_from_this 的实现://也可看boost

template<class _Ty> class enable_shared_from_this
 { // provide member functions that create shared_ptr to this
public:
 typedef _Ty _EStype;

 shared_ptr<_Ty> shared_from_this()
  { // return shared_ptr
  return shared_ptr<_Ty>(_Wptr);
  }

 shared_ptr<const _Ty> shared_from_this() const
  { // return shared_ptr
  return shared_ptr<const _Ty>(_Wptr);
  }

protected:
 enable_shared_from_this()
  { // construct (do nothing)
  }

 enable_shared_from_this(const enable_shared_from_this& _Right)
  : _Wptr(_Right._Wptr)
  { // construct
  }

 enable_shared_from_this& operator=(const enable_shared_from_this& _Right)
  { // assign
  _Wptr = _Right._Wptr;
  return *this;
  }

 ~enable_shared_from_this()
  { // destroy (do nothing)
  }

private:
 template<class _Ty1,
  class _Ty2>
  friend void _Do_enable(
   _Ty1 *,
   enable_shared_from_this<_Ty2>*,
   _Ref_count_base *);

 mutable weak_ptr<_Ty> _Wptr;
 };


enable_shared_from_this 的member可是一个weak_ptr.

当然,从enable_shared_from_this继承后,遇到shared_ptr后,member _Wptr 是怎样工作的,另有玄机。 可以设断点在 _Do_enable 里,有助于理解。

看似简单的share_ptr, 被实现的看似危机四伏。

posted @ 2012-04-07 11:57 多彩人生 阅读(413) | 评论 (0)编辑 收藏

mutable关键字

mutalbe的中文意思是“可变的,易变的”,跟constant(既C++中的const)是反义词。

  在C++中,mutable也是为了突破const的限制而设置的。被mutable修饰的变量,将永远处于可变的状态,即使在一个const函数中。

  我们知道,如果类的成员函数不会改变对象的状态,那么这个成员函数一般会声明成const的。但是,有些时候,我们需要在const的函数里面修改一些跟类状态无关的数据成员,那么这个数据成员就应该被mutalbe来修饰。

  下面是一个小例子:

class ClxTest
{
 public:
  void Output() const;
};

void ClxTest::Output() const
{
 cout << "Output for test!" << endl;
}

void OutputTest(const ClxTest& lx)
{
 lx.Output();
}

  类ClxTest的成员函数Output是用来输出的,不会修改类的状态,所以被声明为const的。

  函数OutputTest也是用来输出的,里面调用了对象lx的Output输出方法,为了防止在函数中调用其他成员函数修改任何成员变量,所以参数也被const修饰。

   如果现在,我们要增添一个功能:计算每个对象的输出次数。如果用来计数的变量是普通的变量的话,那么在const成员函数Output里面是不能修改该 变量的值的;而该变量跟对象的状态无关,所以应该为了修改该变量而去掉Output的const属性。这个时候,就该我们的mutable出场了——只要 用mutalbe来修饰这个变量,所有问题就迎刃而解了。

  下面是修改过的代码:

class ClxTest
{
 public:
  ClxTest();
  ~ClxTest();

  void Output() const;
  int GetOutputTimes() const;

 private:
  mutable int m_iTimes;
};

ClxTest::ClxTest()
{
 m_iTimes = 0;
}

ClxTest::~ClxTest()
{}

void ClxTest::Output() const
{
 cout << "Output for test!" << endl;
 m_iTimes++;
}

int ClxTest::GetOutputTimes() const
{
 return m_iTimes;
}

void OutputTest(const ClxTest& lx)
{
 cout << lx.GetOutputTimes() << endl;
 lx.Output();
 cout << lx.GetOutputTimes() << endl;
}

  计数器m_iTimes被mutable修饰,那么它就可以突破const的限制,在被const修饰的函数里面也能被修改。

posted @ 2012-04-05 16:50 多彩人生 阅读(231) | 评论 (0)编辑 收藏

using namespace

// myclass.h
using namespace std;  // 所有包含myclass.h的文件对std都可见,  所以一般不要将它放在头文件中,以免污染全局空间
class myclass
{
}

///////////////////////////////////////////////////////////

// myclass.h
class myclass
{
      
using namespace std;  // 错, 不能放在类原型中
}


///////////////////////////////////////////////////////////

// myclass.h
class myclass
{
     
void foo()
     {
         
using namespace std;   // 正确, std只本函数可见
         list<int> col;
     }
}


////////////////////////////////////////////////////////////

// myclass.h
class myclass
{
      
void foo();
}

// myclass.cpp
void myclass::foo()
{
      
using namespace std; // 正确, std只本函数可见
}

posted @ 2012-04-05 14:33 多彩人生 阅读(186) | 评论 (0)编辑 收藏

wxWidgets+boost::asio "socket_types.hpp(22) : fatal error C1189: #error : WinSock.h has already been included"

http://blog.csdn.net/gzlyb/article/details/5870326

因为wxWidgets 里已经include "Winsock.h"
在网上找了解决方法:
http://boost.2283326.n4.nabble.com/quot-WinSock-h-has-already-been-included-quot-problem-with-asio-and-VC-2010-td3574900.html
两种方法都可行

"WinSock.h has already been included" : problem with asio and VC++2010

Claude

Hi!

I use a boost asio library in my program. When I compile with Visual C++ obtain this error:

[...]\boost_1_45_0\boost\asio\detail\socket_types.hpp(22): fatal error C1189: #error :  WinSock.h has already been included

How can I fix this error?


Reply | Threaded |   star

Re: "WinSock.h has already been included" : problem with asio and VC++2010

michi7x7-2

> Hi!
Hello,

> I use a boost asio library in my program. When I compile with Visual C++
> obtain this error:
>
> [...]\boost_1_45_0\boost\asio\detail\socket_types.hpp(22): fatal error
> C1189: #error :  WinSock.h has already been included
>
> How can I fix this error?

Try to include asio before including any other Windows-Headers, or use
WinSock2.h instead of WinSock.

Best Regards,

michi7x7

_______________________________________________
Boost-users mailing list
[hidden email]
http://lists.boost.org/mailman/listinfo.cgi/boost-users
Reply | Threaded |   star

Re: "WinSock.h has already been included" : problem with asio and VC++2010

Hee-young Kim
In reply to this post by Claude
If you use "Windows.h" library, set "#define WIN32_LEAN_AND_MEAN" in "stdafx.h" or a suitable place to avoid the duplication.

from Hee-young
Reply | Threaded |   star

Re: "WinSock.h has already been included" : problem with asio and VC++2010

Claude
I solved the problem, thanks!

posted @ 2012-04-05 13:25 多彩人生 阅读(2603) | 评论 (0)编辑 收藏

Double-checked locking真的有效吗?

Double-checked locking真的有效吗?

作者: zsxwing 日期: 2011-04-29 10:48:06

在很多设计模式的书籍中,我们都可以看到类似下面的单例模式的实现代码,一般称为Double-checked locking(DCL)

01public class Singleton {
02 
03    private static Singleton instance;
04 
05    private Singleton() {
06        // do something
07    }
08 
09    public static Singleton getInstance() {
10        if (instance == null) {//1
11            synchronized (Singleton.class) {//2
12                if (instance == null) {//3
13                    instance = new Singleton();//4
14                }
15            }
16        }
17        return instance;
18    }
19}

这样子的代码看起来很完美,可以解决instance的延迟初始化。只是,事实往往不是如此。

问题在于instance = new Singleton();这行代码。

在我们看来,这行代码的意义大概是下面这样子的

 

 

	mem = allocate();             //收集内存 
ctorSingleton(mem); //调用构造函数
instance = mem; //把地址传给instance
	

 

这行代码在Java虚拟机(JVM)看来,却可能是下面的三个步骤(乱序执行的机制):

 

	mem = allocate();             //收集内存 
instance = mem; //把地址传给instance
	ctorSingleton(instance);      //调用构造函数

 

下面我们来假设一个场景。

  1. 线程A调用getInstance函数并且执行到//4。但是线程A只执行到赋值语句,还没有调用构造函数。此时,instance已经不是null了,但是对象还没有初始化。
  2. 很不幸线程A这时正好被挂起。
  3. 线程B获得执行的权力,然后也开始调用getInstance。线程B在//1发现instance已经不是null了,于是就返回对象了,但是这个对象还没有初始化,于是对这个对象进行操作就出错了。

问题就出在instance被提前初始化了。

解决方案一,不使用延迟加载:

01public class Singleton {
02 
03    private static Singleton instance = new Singleton();
04 
05    private Singleton() {
06        // do something
07    }
08 
09    public static Singleton getInstance() {
10        return instance;
11    }
12}

JVM内部的机制能够保证当一个类被加载的时候,这个类的加载过程是线程互斥的。这样当我们第一次调用getInstance的时候,JVM能够帮我们保证instance只被创建一次,并且会保证把赋值给instance的内存初始化完毕。

解决方案二,利用一个内部类来实现延迟加载:

01public class Singleton {
02 
03    private Singleton() {
04        // do something
05    }
06 
07    private static class SingletonContainer {
08        private static Singleton instance = new Singleton();
09    }
10 
11    public static Singleton getInstance() {
12        return SingletonContainer.instance;
13    }
14}

这两种方案都是利用了JVM的类加载机制的互斥。

方案二的延迟加载实现是因为,只有在第一次调用Singleton.getInstance()函数时,JVM才会去加载SingletonContainer,并且初始化instance。

不只Java存在这个问题,C/C++由于CPU的乱序执行机制,也同样存在这样的问题。

抱歉,我之前的理解有误,DCL在Java中失效的原因是JIT比较激进的优化导致的,在C/C++并不会由于CPU的乱序执行(调用构造函数和赋值这两个操作对CPU来说绝对不会乱序的)产生这个问题。

暂时不知道Java对于这个问题是否修复了。

posted @ 2012-03-31 16:53 多彩人生 阅读(299) | 评论 (0)编辑 收藏

伟大架构师的秘密

http://msdn.microsoft.com/zh-cn/library/aa480041.aspx

所有伟大的架构师都掌握了在抽象的不同层次上概念化解决方案的技能。通过将解决方案组织到离散的层次,架构师可以专注于解决方案的单个方面而忽略所有剩余的复杂性。展示将抽象层次应用到 IT 解决方案的技术,并将其与其他工程学科相比较。

一些架构师在这种复杂性方面明显非常出色,而且在不断进步。在我们的职业生涯中,能与一些真正伟大的分析师和架构师并肩工作是非常幸运的。反思这些经验,我们已经分析出是什么造就了杰出的架构师。

无 一例外,所有伟大的架构师都掌握了在截然不同的抽象层次上概念化解决方案的技能。通过将解决方案组织到离散的层次,架构师可以将精力集中在解决方案的单个 方面而忽略所有剩余的复杂性。他们一旦稳定了解决方案的某个部分,接下来就能继续处理其他方面,从而不断地将层次发展并完善到最终可以被实现的粘合模型 中。

大多数软件开发人员懂得应该将解决方案分解到抽象层次。但是在实际的项目中,这是非常难于付诸实践的。当遇到第一个困难时,在急于开 始编码时是很容易放弃这些层次的。伟大的架构师会经受这些挑战并在整个项目的生命周期中严格保持这些层次。他们意识到,如果不这样做,最终将淹没在复杂性 中。


posted @ 2012-03-31 11:05 多彩人生 阅读(281) | 评论 (0)编辑 收藏

boost::asio::deadline_timer

注意deadline_timer和socket一样,都用 io_service作为构造函数的参数。也即,在其上进行异步操作,都将导致和io_service所包含的iocp相关联。这同样意味着在析构 io_service之前,必须析构关联在这个io_service上的deadline_timer。

一个deadline_timer只维护一个超时时间,一个deadline_timer不同时维持多个定时器。

void wait();
void
wait(boost::system::error_code & ec);

这是个同步等待函数,例如:

boost::asio::io_service io;
boost::asio::deadline_timer t(io, boost::posix_time::seconds(5));
t.wait();
由于不涉及到异步,该函数和io_service没什么关系。这个函数在windows下的实现就只是简单的Sleep。因此也就不存在cancel之说。

如果t的expire时间已过,那么t.wait会立刻返回。

例如如下代码:

boost::asio::io_service io; 
boost::asio::deadline_timer t(io, boost::posix_time::seconds(5));
t.wait();
t.wait();

第一个t.wait会等待5s才返回,第2个t.wait会立刻返回。

wait函数本身没有参数,不存在t.wait(seconds(5))的用法。

可以在构造deadline_timer时指定时间。

basic_deadline_timer(
boost::asio::io_service & io_service);

basic_deadline_timer(
boost::asio::io_service & io_service,
const time_type & expiry_time);

basic_deadline_timer(
boost::asio::io_service & io_service,
const duration_type & expiry_time);

注意后两种的区别。以下2种用法是等价的:

boost::asio::deadline_timer t(io, boost::posix_time::microsec_clock::universal_time()+boost::posix_time::seconds(5));

boost::asio::deadline_timer t(io, boost::posix_time::seconds(5));

前者是绝对时间,后者是相对时间。

除了在deadline_timer构造函数中指定时间,也可以使用如下2个函数指定时间:

expires_at,expires_from_now。这两个函数的区别是前者参数是绝对时间,后者是相对时间。例如:

boost::asio::io_service io;

boost::asio::deadline_timer t(io);

t.expires_from_now(boost::posix_time::seconds(5));

t.wait();

注意这两个函数除了设定下次超时时间之外,还有一个效果是取消前面所有的异步wait。详情参看关于这两个函数的详细解释。

template<
    typename
WaitHandler>
void async_wait(
    WaitHandler handler);
其中void handler(
const boost::system::error_code& error // Result of operation.
);

注意这个error很重要,表明这个handler是因为超时被执行还是因为被cancel。
符合2种情况之一,handler被执行:超时或者被cancel。
这同时隐含的说明了除非io.stop被调用,否则handler一定会被执行。即便是被cancel。
被cancel有多种方法,直接调用cancel或者调用expires_at,expires_from_now重新设置超时时间。
void handle_wait(const boost::system::error_code& error,
boost::asio::deadline_timer& t,int& count)
{
if(!error)
{
std::cout<< count<<"\n";
if(count++<5)
{
t.expires_from_now(boost::posix_time::seconds(1));
t.async_wait(boost::bind(handle_wait,boost::asio::placeholders::error,
boost::ref(t),boost::ref(count)));
}
}
}

int main()
{
boost::asio::io_service io;
boost::asio::deadline_timer t(io);
size_t a = t.expires_from_now(boost::posix_time::seconds(1));
int count = 0;
t.async_wait(boost::bind(handle_wait,boost::asio::placeholders::error,
boost::ref(t),boost::ref(count)));
io.run();
return 0;
}

deadline_timer的析构函数什么也不做,因此不会导致发出的async_wait被cancel。

std::size_t cancel();

std::size_t
cancel(
    boost::system::error_code & ec);
此函数调用会导致所有尚未返回的async_wait(handler)的handler被调用,同时error_code为boost::asio::error::operation_aborted。返回值是被cancel的timer数量。

 time_type expires_at() const;

std::size_t
expires_at(
const time_type & expiry_time);

std::size_t
expires_at(
const time_type & expiry_time,
boost::system::error_code & ec);
duration_type expires_from_now() const;

std::size_t
expires_from_now(
const duration_type & expiry_time);

std::size_t
expires_from_now(
const duration_type & expiry_time,
boost::system::error_code & ec);
以上2组函数用来设置新的超时时间,同时cancel所有未完成的async_wait操作。注意这两个函数的返回值即为cancel的操作数量。
考虑如下场景,我们有一个workerthread正在调用io_work.run();

此时主线程向workerthread发出了一个异步调用,例如post(...),考虑到io_work.run很可能积压了很多handlers没有处理,或者某些handlers处理非常耗时,希望它在5s内必须返回。那么可以:

void handle_wait(const boost::system::error_code& error,bool& Ret)
{
    if(!error) Ret = false;
}

void handle_func(
    boost::shared_ptr<boost::asio::deadline_timer> t,
    boost::shared_ptr<boost::asio::io_service> io,
    int* v)
{
    boost::asio::io_service::work work(*io);

    if(t->cancel()>0)
    {       
        *v = 1;
    }
}

void func_delay_1_second()
{
    boost::asio::io_service io;
    boost::asio::deadline_timer t(io,boost::posix_time::seconds(1));
    t.wait();
}

bool sync_func(int& v,boost::asio::io_service& io_work)
{
    boost::shared_ptr<boost::asio::io_service> io(new boost::asio::io_service);
    boost::shared_ptr<boost::asio::deadline_timer> t(new boost::asio::deadline_timer(*io));
    t->expires_from_now(boost::posix_time::seconds(5));
    bool ret = true;
    t->async_wait(boost::bind(handle_wait,boost::asio::placeholders::error,boost::ref(ret)));
    io_work.post(boost::bind(handle_func,t,io,&v));
    io->run();
    return ret;
}

int main()
{
    boost::asio::io_service io_work;
    auto_ptr<boost::asio::io_service::work> work(new boost::asio::io_service::work(io_work));
    boost::thread workthread(boost::bind(&boost::asio::io_service::run, &io_work));
    for(int i=0;i<3;++i) io_work.post(func_delay_1_second);

    int v = 0;
    bool ret = sync_func(v,io_work);
    if(ret) printf("v %d\n",v);

    work.reset();
    workthread.join();
    return 0;
}

上面代码中如果先进入handle_wait,则表明超时,此时设置ret = false,然后io.run会退出,表明调用失败,如果稍后进入handle_func,则t->cancel会返回0,也不做任何操作。虽然在 io.run退出时会释放v,但由于handle_func不做任何操作因此也不会引起任何安全问题。如果handle_func先进入,则首先使用 work让io.run不会退出,然后取消timer,并且设置,随后work析构,io.run会退出。注意这里面的同步问题:如果先进入 handle_wait,随后进入handle_func,那么handle_func中的t->cancel会返回0从而不做任何事。如果先进入 handle_func,随后进入handle_wait,那么t->cancel或者返回0或者返回1,由于使用了work,io.run也不会 退出。注意这里的t和io都是shared_ptr的,否则因为如果handle_wait先返回,则io.run会立刻退出并析 构,handle_func中将使用悬空的t和io,将导致非法操作。注意这里的io必须是shared_ptr的,如果 boost::asio::io_service::work work(*io); 改成work(t->get_ioservice());则t是有效的,而t所索引的io_service已经无效了,同样会导致非法操作。牢记 io_service的使用原则:必须首先析构所有索引的其他对象之后才能析构io_service。

posted @ 2012-03-30 16:39 多彩人生 阅读(2202) | 评论 (1)编辑 收藏

RAII

 RAII是“资源获取就是初始化”的缩语(Resource Acquisition Is Initialization),是一种利用对象生命周期来控制程序资源(如内存、文件句柄、网络连接、互斥量等等)的简单技术。   RAII 的一般做法是这样的:在对象构造时获取资源,接着控制对资源的访问使之在对象的生命周期内始终保持有效,最后在对象析构的时候释放资源。借此,我们实际上把管理一份资源的责任托管给了一个对象。这种做法有两大好处:   1,我们不需要显式地释放资源。   2,采用这种方式,对象所需的资源在其生命期内始终保持有效 —— 我们可以说,此时这个类维护了一个 invariant。这样,通过该类对象使用资源时,就不必检查资源有效性的问题,可以简化逻辑、提高效率。

posted @ 2012-03-29 21:20 多彩人生 阅读(209) | 评论 (0)编辑 收藏

wxWidgets

安装好以后首先要编译。

1、   登陆http://www.wxwidgets.org/,下载wxMSW-2.8.8-Setup.exe

2、   运行wxMSW-2.8.8-Setup.exe,将wxWidgets安装到D:\wxWidgets-2.8.8

3、   安装完毕后还需要进行编译,要求有IDE,我用的是MS Visual Studio 2008

4、   进入D:\wxWidgets-2.8.8\build\msw,运用MS Visual Studio 2008打开wx.dsw或者wx_dll.dsw(或者两者都编译),因为.dsw文件是vc6的工程文件,点确定将所有文件进行转换,然后点击Build->Configuration Manager,弹出窗口,选择Active solution configurationUnicode Debug或是别的,如果需要其中多个solution configuration,可以依次选中,然后依次按下F7Build solution,我分别选中了Unicode DebugUnicode Release,编译完成后会在D:\wxWidgets-2.8.8\lib下生成vc_lib文件夹,其中包括生成的相应的.lib等文件和 mswud文件夹。到此,wxWidgets安装完毕。

【注意】wxbase28ud.lib中的ud代表Unicode Dug版本,相应地wxbase28u.lib中的u代表的是UnicodeRelease版本。Unicode是统一的字符编码标准,采用双字节对字符进行编码,支持多语言,有利于国际化,处理更方便,所以选择编译成Unicode版本。


工程中需要添加 wxWidget 的头文件目录:

%installdir%\include\msvc
%installdir%\include

以及库目录:

%installdir%\lib\vc_lib

另外如果是普通 Win32 工程的话,还需要链接额外的库:

comctl32.lib rpcrt4.lib 

posted @ 2012-03-29 16:48 多彩人生 阅读(354) | 评论 (0)编辑 收藏

stdio.h cstdio

   #include<cstdio>  

2010-01-26 23:25:29|  分类: 编程 |字号 订阅

在新的C++标准中,生成新头文件 的方法仅仅是将现有C++头文件名中的.h去掉。例如,<iostream.h>变成了< iostream>,<complex.h>变成了<complex>,等等。对于C头文件,采用同样的方法,但在每个名 字前还要添加一个c。所以C的<string.h>变成了<cstring>,<stdio.h>变成了< cstdio>,等等。    
  旧的C++头文件是官方所反对使用的(即,明确列出不再支持),但旧的C头文件则没有(以保持对C的兼容性)。    
  下面是C++头文件的现状:    
  ·     旧的C++头文件名如<iostream.h>将会继续被支持,尽管它们不在官方标准中。这些头文件的内容不在名字空间std中。    
  ·     新的C++头文件如<iostream>包含的基本功能和对应的旧头文件相同,但头文件的内容在名字空间std中。(在标准化的过程中,库中有些部分的细节被修改了,所以旧头文件和新头文件中的实体不一定完全对应。)    
  ·     标准C头文件如<stdio.h>继续被支持。头文件的内容不在std中。    
  ·     具有C库功能的新C++头文件具有如<cstdio>这样的名字。它们提供的内容和相应的旧C头文件相同,只是内容在std中。

如果编译器同时支持<iostream>和  
  <iostream.h>   。如果使用了#include  
  <iostream>,   得到的是置于名字空间std下的iostream   库的元素;  
  如果使用#include   <iostream.h>,得到的是置于全局空间的同样的元素。在全  
  局空间获取元素会导致名字冲突,而设计名字空间的初衷正是用来避免这种名  
  字冲突的发生.
#if           _MSC_VER   >   1000  
  #pragma   on
ce  
  #endif  
   
  #ifndef   _CSTDIO_  
  #define   _CSTDIO_  
  #ifdef   _STD_USING  
    #undef   _STD_USING  
    #include   <stdio.h>  
    #define   _STD_USING  
  #else  
    #include   <stdio.h>  
  #endif   /*   _STD_USING   */  
  #endif   /*   _CSTDIO_   */  
   
  上面就是cstdio的全部内容(vc6)  
  好像只是include   <stdio.h>而已!!!

posted @ 2012-03-29 16:38 多彩人生 阅读(474) | 评论 (0)编辑 收藏

仅列出标题
共25页: First 17 18 19 20 21 22 23 24 25 

导航

统计

常用链接

留言簿(3)

随笔分类

随笔档案

搜索

最新评论

阅读排行榜

评论排行榜