类中成员变量和成员函数在内存中的地址

#include <iostream>
using namespace std;

class Test
{
public:
 int a;
 int b;
 void print();
 void s();
 void ss();
 void fs();
};
void Test::print()
{
 //cout << "hello" << endl;
}

void Test::s()
{

}

void Test::ss()
{

}
void Test::fs()
{

}


void f()
{
 int s = 3;
 cout << "&s" << &s << endl;
 cout << "f" << endl;
}

class B:Test
{

};

int main()
{
 Test t;
 cout << sizeof(t) << endl;
 cout << &t.a << endl;
 cout << &t.b << endl;
 Test tt;
 cout << &tt.a << endl;
 cout << &tt.b << endl;
 typedef void (Test::*p)(void);
 ////Test t;
 ////t.print();
 p fun = &Test::print;
 printf("%p\n",fun);
 fun = &Test::s;
 printf("%p\n",fun);

 fun = &Test::ss;
 printf("%p\n",fun);
 fun = &Test::fs;
 printf("%p\n",fun);
 f();
 cout << "--------" << endl;
 B b;
 cout << sizeof(b) << endl;
 ////((Test::*print)fun)();
 //Test *p4;
 //fun(p4);
 //  Test t;
 //  (t.*fun)();
 //  Test d;
 //  (d.*fun)();
}


类的成员函数不是在类实例化的时候载入内存的。应该是编译链接的时候就在程序文件中确定了相对地址。然后程序载入的时候,所有的函数都载入到内存的代码区。所以实例化对象的时候,只是申请了对象的成员变量的地址,成员函数对于所有的类对象来说,应该只有一份,在代码区共用。而且类的成员变量和成员函数不是存放在一起(地址不是连续的,是分开存放的)
Test类中的a,b变量地址是连续的,每个占4字节。但是s(),ss(),fs()不是和a,b连续的,而且,这些函数之间,好像也并不是严格连续的,改一下函数名,地址有可能会变化

posted @ 2011-03-25 19:57 MrRightLeft 阅读(1049) | 评论 (0)编辑 收藏

aaa

<table height="1" cellspacing="0" cellpadding="0" border="0"><tr><td height="1"><embed src="http://www.myheritagefiles.com/video/Z/28/a2ay84_51334487wd8141f389ika4" width="340" height="340" type="application/x-shockwave-flash" wmode="transparent"></embed></td></tr></table><p><a href="http://www.myheritage.cn"  >MyHeritage</a>: <a href="http://www.myheritage.cn"  >家谱</a> - <a href="http://www.myheritage.cn/%E6%97%8F%E8%B0%B1%E7%A0%94%E7%A9%B6"  >族谱研究</a> - <a href="http://www.myheritage.cn/%E5%90%8D%E4%BA%BA"  >名人</a>



posted @ 2011-03-23 16:37 MrRightLeft 阅读(57) | 评论 (0)编辑 收藏

人脸识别学习路线

1.最流行的方法:主成分分析(Principal Component Analisis,PCA)和线性判别分析(Linear Discriminant Analysis,LDA)
                               相关论文:PCA ,Face Recognition using Eigenfaces             LDA,Based on an optimized LDA algorithm for face recognition

2.流形学习算法:  等距离映射(Isometric mapping,Isomap),局部线性嵌入(locally linear embedding, LLE),拉普拉斯特征映射(laplacian eigenmap)和局部保持投影(Locality Preserving Projections,LPP)等
                              相关论文:  Isomap,  global geometric framework for nonlinear dimensionality reduction    LLE, Nonlinear dimentionality reduction by locally linear embedding.    laplacian eigenmap, Laplacian eigenmaps for dimensionality reduction and data representation .    LPP, Learning a locality discriminanting projection for classification.  

posted @ 2011-03-20 09:23 MrRightLeft 阅读(570) | 评论 (0)编辑 收藏

Singleton的设计--经典

转自:http://www.techmango.com/blog/article/DotNet/Thread_Safe_Singleton_Instance.htm
许多同志都会采用一个double check的方式来创建一个Singleton:

public class Singleton
{
    protected Singleton() { }
    private static volatile Singleton instance = null;
    /// Lazy方式创建唯一实例的过程
    public static Singleton Instance()
    {
        if (instance == null)         // 外层if
            lock (typeof(Singleton))      // 多线程中共享资源同步
                if (instance == null) // 内层if
                    instance = new Singleton();
        return instance;
    }
}
 

这应该是比较经典的线程安全的Singleton创建方式,但是还是一个更加简单也很Cool的线程安全的Singleton:

class Singleton
{
    private Singleton() { }
    public static readonly Singleton Instance = new Singleton();
}
 

  它省去了上面示例中那个laze构造过程,由于Instance是类的公共静态成员,因此相当于它会在类第一次被用到的时候被构造,同样的原因也就可以省去把它放在静态构造函数里的过程。


这里实例构造函数被彻底定义为私有的,所以客户程序和子类无法额外构造新的实例,所有的访问通过公共静态成员Instance获得唯一实例的引用,符合Singleton的设计意图。

posted @ 2011-03-09 12:36 MrRightLeft 阅读(243) | 评论 (0)编辑 收藏

c++学习之---volatile和线程安全的singleton模式

参考:http://www.cnblogs.com/rocketfan/archive/2009/12/05/1617759.html
volatile:
1.volatile的作用:
(1) the content of a volatile variable is “unstable” (can change by means unknown to the compiler),

(2) all writes to volatile data are “observable” so they must be executed religiously, and

(3) all operations on volatile data are executed in the sequence in which they appear in the source code.
1.被声明为volatile的变量其内容是不稳定的(unstable),它的值有可能由编译器所不能知晓的情况所改变。
2.所有对声明为volatile的变量的写操作都是可见的,必须严格执行be executed religiously。
3.所有对声明为volatile的变量的操作(读写)都必须严格按照源代码的顺序执行。
volatile确保每次直接从内存读取变量的值。java中的volatile是跨线程保证上述三个条件的,而C++只是单一线程内保证。
但是即使是JAVA能够跨越线程保证,仍然是不够的因为volatile和非volatile操作之间的顺序仍然是未定义的,有可能产生问题,考虑下面的代码:

volatile int vi;

void bar(void) {
vi = 1;
foo();
vi = 0;
}

我们一般会认为vi会在调用foo之前设置为1,调用完后会被置为0。然而编译器不会对你保证这一点,它会很高兴的将你的foo()移位,比如跑到vi = 1前面,只要它知道在foo()里不会涉及到其它的volatile操作。所以安全的方法是用栅栏memory barrier例如“asm volatile (”" ::: “memory”)加到foo的前面和后面 来保证严格的执行顺序。内存屏障保证代码执行时严格按照源代码的的顺序。

posted @ 2011-03-09 11:47 MrRightLeft 阅读(729) | 评论 (0)编辑 收藏

main函数之前干了神马?-谁调用了我的main

(转载自http://topic.csdn.net/u/20101013/16/e5f2fcbb-528f-4b1a-b85c-aaa8aa9ab3b6.html
main函数之前--真正的函数执行入口或开始

一种解释

实际上,在可执行文件被加载之后,控制权立即交给由编译器插入的Start函数,它将对后面这些全局变量进行准备:
   _osver 操作系统的构件编号
  _winmajor 操作系统的主版本号
  _winminor 操作系统的次版本号
  _winver 操作系统完全版本号
  __argc 命令行参数个数
  __argv 指向参数字符串的指针数组
  _environ 指向环境变量字符串的指针数组
Start函数初始化堆并调用main函数.mian函数返回之后,Start函数调用Exit函数结束该进程.
启动函数Start的源代码在:
   crt0.c Microsoft Visual C++
  c0w.asm Borladn C++

另一种解释

Some of the stuff that has to happen before main():  
set up initial stack pointer  
initialize static and global data  
zero out uninitialized data  
run global constructors

Some of this comes with the runtime library's crt0.o file or its __start() function. Some of it you need to do yourself.
Crt0 is a synonym for the C runtime library.  
Depending on the system you're using the follwing may be incomplete, but it should give you an idea. Using newlib-1.9.0/libgloss/m68k/crt0.S as an outline, the steps are:  
1. Set stack pointer to value of __STACK if set  
2. Set the initial value of the frame pointer  
3. Clear .bss (where all the values that start at zero go)  
4. Call indirect of hardware_init_hook if set to initialize hardware  
5. Call indirect of software_init_hook if set to initialize software  
6. Add __do_global_dtors and __FINI_SECTION__ to the atexit function so destructors and other cleanup functions are called when the program exits by either returning from main, or calling exit  
7. setup the paramters for argc, argv, argp and call main  
8. call exit if main returns

第三种解释:囫囵C语言(三):谁调用了我的 main?
    
    现在最重要的是要跟得上潮流,所以套用比较时髦的话,谁动了我的奶酪。谁调用了我的 main?不过作为计算机工作者,我劝大家还是不要赶时髦,今天Java热,明天 .net 流行,什么时髦就学什么。我的意思是先花几年把基本功学好,等你赶时髦的时候也好事半功倍。废话不多说了。
    
    我们都听说过一句话:“main是C语言的入口”。我至今不明白为什么这么说。就好像如果有人说:“挣钱是泡妞”,肯定无数砖头拍过来。这句话应该是“挣钱是泡妞的一个条件,只不过这个条件特别重要”。那么上面那句话应该是 “main是C语言中一个符号,只不过这个符号比较特别。”
    
    我们看下面的例子:
    
    /* file name test00.c */
    
    int main(int argc, char* argv)
    {
     return 0;
    }
    
    编译链接它:
    cc test00.c -o test.exe
    会生成 test.exe
    
    但是我们加上这个选项: -nostdlib (不链接标准库)
    cc test00.c -nostdlib -o test.exe
    链接器会报错:
    undefined symbol: __start
    
    也就是说:
    1. 编译器缺省是找 __start 符号,而不是 main
    2. __start 这个符号是程序的起始点
    3. main 是被标准库调用的一个符号
    
    再来思考一个问题:
    我们写程序,比如一个模块,通常要有 initialize 和 de-initialize,但是我们写 C 程序的时候为什么有些模块没有这两个过程么呢?比如我们程序从 main 开始就可以 malloc,free,但是我们在 main 里面却没有初始化堆。再比如在 main 里面可以直接 printf,可是我们并没有打开标准输出文件啊。(不知道什么是 stdin,stdout,stderr 以及 printf 和 stdout 关系的群众请先看看 C 语言中文件的概念)。
    
    有人说,这些东西不需要初始化。如果您真得这么想,请您不要再往下看了,我个人认为计算机软件不适合您。
    
    聪明的人民群众会想,一定是在 main 之前干了些什么。使这些函数可以直接调用而不用初始化。通常,我们会在编译器的环境中找到一个名字类似于 crt0.o 的文件,这个文件中包含了我们刚才所说的 __start 符号。(crt 大概是 C Runtime 的缩写,请大家帮助确认一下。)
    
    那么真正的 crt0.s 是什么样子呢?下面我们给出部分伪代码:
    
    ///////////////////////////////////////////////////////
    section .text:
    __start:
    
     :
     init stack;
     init heap;
     open stdin;
     open stdout;
     open stderr;
     :
     push argv;
     push argc;
     call _main; (调用 main)
     :
     destory heap;
     close stdin;
     close stdout;
     close stderr;
     :
     call __exit;
    ////////////////////////////////////////////////////
    
    实际上可能还有很多初始化工作,因为都是和操作系统相关的,笔者就不一一列出了。
    
    注意:
    1. 不同的编译器,不一定缺省得符号都是 __start。
    2. 汇编里面的 _main 就是 C 语言里面的 main,是因为汇编器和C编译器对符号的命名有差异(通常是差一个下划线'_')。
    3. 目前操作系统结构有两个主要的分支:微内核和宏内核。微内核的优点是,结构清晰,简单,内核组件较少,便于维护;缺点是,进程间通信较多,程序频繁进出内核,效率较低。宏内核正好相反。我说这个是什么目的是:没办法保证每个组件都在用户空间(标准库函数)中初始化,有些组件确实可能不要初始化,操作系统在创建进程的时候在内核空间做的。这依赖于操作系统的具体实现,比如堆,宏内核结构可能在内核初始化,微内核结构在用户空间;即使同样是微内核,这个东东也可能会被拿到内核空间初始化。
    
    随着 CPU 技术的发展,存储量的迅速扩展,代码复杂程度的增加,微内核被越来越多的采用。你会为了 10% 的效率使代码复杂度增加么?要知道每隔 18 个月 CPU 的速度就会翻一番。所以我对程序员的要求是,我首先不要你的代码效率高,我首先要你的代码能让 80% 的人迅速看懂并可以维护。

总结:

main函数执行之前,主要就是初始化系统相关资源:

1.设置栈指针

2.初始化static静态和global全局变量,即data段的内容

3.将未初始化部分的赋初值:数值型short,int,long等为0,bool为FALSE,指针为NULL,等等,即.bss段的内容

4.运行全局构造器,估计是C++中构造函数之类的吧

5.将main函数的参数,argc,argv等传递给main函数,然后才真正运行main函数

posted @ 2011-03-08 23:34 MrRightLeft 阅读(2637) | 评论 (0)编辑 收藏

RAII

1.RAII:
借用局部对象资源管理的概念。即在一个作用域中的局部对象,在程序运行超过该作用域后,该对象被自动销毁。

2.PIMPL:
PIMPL惯用手法的作用是解开类的使用接口和实现的耦合。涉及紧耦合和松耦合的概念。松耦合对于编译时有好处的。举例说明如下:
#include<x.hpp>
class C
{
      public:
            void f1();
      private:
            X x; //与X的强耦合
};
如上面的代码,C与X的实现就是强耦合的。从语义角度来讲(或者从封装的角度来讲),X是C的实现的一部分,不应该暴露给客户,它对客户应该是透明的。以上的强耦合,导致如果X的实现部分被更改,则在编译的时候,不仅X要重新编译一次,就连C也要受到牵连。解决这个途径就是采用PIMPL手法.即将C中X的对象,改为指向X对象的指针。使用指针有效得隔离了X的实现。且不需要包含X的头文件,即#include<x.hpp>这一句可以省略。
使用PIMPL修改后的类如下:
class X; //用前置声明来取代include<x.hpp>
class C
{
      ...
      private:
            X* pImpl; //声明一个X*的时候,class X不用完全定义
};
在一个既定的平台上,任何指针的大小都是相同的。这样修改X的定义,就不会影响到类C了。不会出现“城门失火,殃及池鱼。”就是因为护城河离城门远了(松耦合)。

3.设计模式之-工厂模式和与策略模式






posted @ 2011-03-08 21:04 MrRightLeft 阅读(195) | 评论 (0)编辑 收藏

仅列出标题
共4页: 1 2 3 4 
<2024年5月>
2829301234
567891011
12131415161718
19202122232425
2627282930311
2345678

导航

统计

随笔分类

随笔档案

文章分类

文章档案

搜索

最新评论

阅读排行榜

评论排行榜