this 指针可以被用来修改其指向的类对象也可以用同一类型的新对象覆盖该对象例
如下面是类classType 的成员函数assign() 你能说明它的功能吗
classType& classType::assign( const classType &source )
{
if ( this != &source )
{
this->~classType();
new (this) classType( source );
}
return *this;
}
记住~classType()是析构函数的名字new 表达式看起来可能有点滑稽但是我们已经
在8.4 节看到过这种被称为定位new 表达式placement new expression 的new 表达式
你对这种编码风格有何看法你认为这是一种安全的操作吗?为什么?这个作业题,哪位给解释下?个人不喜欢这种编码风格。

解决方案 »

  1.   

    倘若拷贝构造函数抛出异常,而原对象之前已惨遭析构,此时即使catch到异常也回天无力了。另外,如果析构函数是虚的,而assign不是虚的,那在特殊情况下还会导致对象“变质”,当然,你可以说那是因为类设计得太变态。除此之外,还真没想出其它不妥的地方。
      

  2.   

    二楼很强大。
    this->~classType();这个不安全,考虑类继承的话。换成 delete this;
    拷贝构造函数抛出异常?除非有明确的实现,默认应该不可能吧。
      

  3.   

    这是<<C++ Primer>>的一个作业题。看来大家都没有真正仔细的读过这本书。
      

  4.   

    delete this不好,会存在释放,而后又要重新分配
      

  5.   

    new (this) classType( source );
    这句是什么意思?求高手解释
      

  6.   


    delete this 才会不安全吧!
    如果类有继承关系,那么使用虚析构函数的话,直接如此显式调用析构函数仍然可以保证正确的调用。
    相反如果this是在stack上分配的,delete只会导致出错。这还不提效率的问题。
      

  7.   


    定位放置(placement)new ,就是new不再管你的空间分配,而是直接使用你传进来的指针指向的空间。(这里是this)整个代码就是为了让assign不再有重新分配的开销吧,搞的如此别扭。隐患的话就是构造可能的异常抛出了。
      

  8.   

    被抛弃的风格,不要用。除非你自己malloc,或是new
      

  9.   

    比较强大的用法啊.
    感觉这里
    this->~classType();
    这里是不能用delete的.因为delete会释放资源
    然后
    new (this) classType( source );
    就没有存储空间了.
      

  10.   

    如果用delete this就完全错了,不只是“特殊情况下有缺点”这么简单了。
      

  11.   

    place new吧,实际上还是在当前对象的内存上拷贝构造,那个析构不会去释放内存的。
    所以要保证析构函数和拷贝构造不异常。1楼已经说的很好了。
      

  12.   

    catch到异常之后怎么就无力回天了呢?  
     如果析构函数是虚的,而assign不是虚的,那在特殊情况下还会导致对象“变质”,这里“变质”是什么意思,析构函数调用不完全?特殊情况是?
      

  13.   

    new(space pointer) constructor; // 指定空间assign() 隐含的两个问题出现在以下情况:
    1、析构函数不是virtual的;
    2、类声明中有需要深拷贝的情况。
      

  14.   

    从安全的角度来讲,这段代码是没有问题的。1.构造函数抛出异常并非是这段代码的隐患。如果抛出异常,不但这块调用会出现问题,任何试图构造该类型对象的地方都会出现问题。程序员应该避免在构造、析构函数中抛出异常。2.多态引起的问题。
      2.1 如果该类用于多态,其析构函数必然为 virtual, 否则这是一个不合格的 C++ 程序员  2.2 assign 不是虚函数  从现实意义这个角度来讲,其不应该设计为虚函数。在这种情况下,类似于下面的调用 pa->assign( xx ) 是不合理的。  2.3 assign 为虚函数。在这种情况下没有任何问题。
      

  15.   

     为什么pa->assign( xx )是不合理的?
      

  16.   

    确实这里不能用delete this.
    当时只想着直接调用 this->~classType(); 如果继承基类的析构函数不是虚的话,会不被调用。专门写了个代码,进行测试。结果是即便基类的析构函数不是虚的,直接调用继承类的析构函数,基类的析构函数也会被调用。最开始看到的时候,以为是一段很有技巧的深拷贝函数。不过,根椐代码的测试情况,浅拷贝都谈不上。测试代码:(vs2010)class TestBase 
    {
    private:
    protected:
    public :
    int m_nInt; TestBase()
    {
    m_nInt = 0;
    } ~TestBase()
    {
    TRACE( "TestBase Destructor.\r\n" );
    } void SetData()
    {
    m_nInt = 1;
    }};
    class Test : public TestBase
    {
    private:
    protected:
    public:
    Test()
    {

    } ~Test()
    {
    TRACE( "Test Destructor.\r\n");
    } Test& assign( const Test &source )
    {
    if ( this != &source )
    {
    this->~Test();
    new Test( source );
    }
    return *this;
    }
    };int  DoTest()
    {
    int nReturn = 0;
    Test TestA;
    Test TestB; TRACE1( "TestA, m_nInt:%d\r\n", TestA.m_nInt );
    TRACE1( "TestB, m_nInt:%d\r\n", TestB.m_nInt ); TestB.SetData(); TRACE1( "TestA, m_nInt:%d\r\n", TestA.m_nInt );
    TRACE1( "TestB, m_nInt:%d\r\n", TestB.m_nInt ); TestA.assign( TestB );

    TRACE1( "TestA, m_nInt:%d\r\n", TestA.m_nInt );
    TRACE1( "TestB, m_nInt:%d\r\n", TestB.m_nInt );
    return nReturn;
    }return nReturn; 之前的输出是TestA, m_nInt:0
    TestB, m_nInt:0
    TestA, m_nInt:0
    TestB, m_nInt:1
    Test Destructor.
    TestBase Destructor.
    TestA, m_nInt:0
    TestB, m_nInt:1
    assign的功能就是释放资源,再执行一次构造函数?还是和编译器有关?
      

  17.   

    先判断传入的对象是不是和当前对象相同。如果不同,先调用析构函数,然后调用构造函数构建Test类的对象,把对象指针传回。就是把原来Private中的内容都弄没了。这个用法有什么意思?直接析构构造不就行了。
      

  18.   

    首先,这种编写方式除了看起来比较怪之外,没有任何问题。其次,很遗憾的是,如果你想要自己做内存分配的话(比如先从系统中申请一大块内存,然后在这块内存里再行分配。事实上,考虑到效率的因素,不论STL还是MFC的所有容器都是自己分配内存的),那么,这种写法是必须的。实际上,这里的this->~classType()和new (this) classType( source )无非是构造和析构函数的显式调用写法而已。平时我们所习惯的,都是构造和析购函数的隐含调用(比如变量声明以及new和delete的附带效果),所以一看到这连个函数的显式调用,就会觉得别扭。殊不知,从C++的语法上来讲,这种写法才是“本质”,而那些隐式调用,不过是为了照顾人的习惯而采用的“等价写法”而已。为了更进一步说明什么是“本质”,不妨想一下这个问题:
    Type *p = new Type,这句里没有任何函数调用的语法格式,凭什么调用了函数Type::Type()?delete p也同样没有任何函数调用的语法格式,凭什么调用了函数Type::~Type()?从语法上来讲,这完全毫无道理。但如果这样写:
    Type *p = malloc(sizeof(Type));   // 分配内存
    new (p) Type();                   // 调用函数Type()
    p->~Type();                       // 调用函数~Type()
    free(p);                          // 释放内存
    事情就非常清楚了。至此,谁更“本质”,不是很清楚吗?说起谁更“本质”,顺便还可以看一个例子:a = b + c,大家看着很舒服,不过,这句话的真正含义,却是一个看起来不那么舒服的东西:operator=(a, operator+(b, c));觉得后面这个别扭?那你又如何理解你所重载出来的operator=和operator+?虽然,没有必要的时候,谁都会写a=b+c,不过,弄清楚a=b+c背后的含义、或者说a=b+c到底是什么东西的简写,对于一个C++程序员来说,确是非常必要的。
      

  19.   


    this->~classType();
    new (this) classType( source );  //这一句,应该很容易迷惑人。实际和下面的代码是等价的。远没有下面的代码清晰。this->~classType();
    classType();
      

  20.   

    classType& classType::assign( const classType &source )更是不明白,带上这个参数有什么作用?
    const classType &source 不知是否和编译器有关,否则的话,这段代码的作者也太大神了。
      

  21.   

    new (this) classType( source )跟classType()完全两回事,前者调用的是拷贝构造函数!
    所以你才不明白const classType &source这个参数的作用。如果没有这个参数,这个函数就只能叫Clear了,怎么能叫assign?
      

  22.   

    另外,classType()的含义并不是调用构造函数,而是构造一个新的classType类型的临时实例。这个临时实例在本句结束后(遇到分号以后)即被析构,因此单独的一句classType();没有任何意义。想调用构造函数,唯一的办法就是:new (p) classType(...);
      

  23.   

    new (this) classType( source )跟classType()完全两回事,前者调用的是拷贝构造函数!最开始我就是这样想的。你运行过我上面写的代码吗?为什么不试一试?想调用构造函数,唯一的办法就是:new (p) classType(...);this->~Test();
    new Test( source ); // 改成 Test();看看有没有效果。反正我的vs2010,是绝对有效的。理论是要能通过验证的。
      

  24.   

    莫名其妙,assign的作用是复制,而你的写法根本连参数source都没用到,如果居然还能“绝对有效”的话,那你的代码可以成为人类灵异事件之首了。给你代码,不同的写法分别是什么结果,你自己测去吧。
    class A
    {
    public:
    int i; A() { i = 0; }
    A(const A& a) { i = a.i; }
    virtual ~A() { i = -1; } void assign(const A& a);
    };void A::assign(const A& a)
    {
    this->~A();
    // A();              // 你的代码
    // new (this) A(a);  // 我的代码
    }void main()
    {
    A a, b; b.i = 2;
    a.assign(b);
    printf("%d", a.i);
    }
      

  25.   

    这个靠谱。
    没有new。
    不需要delete吧。
      

  26.   

    那是因为只能这么写,其他的写法都可能导致错误
    假如调用assign的是对象指针或是引用,用this =  new classType(source) 也没关系
    但如果仅仅是一个对象,那用this = new classType( source ) 会导致严重的错误。
      

  27.   

    那你的代码可以成为人类灵异事件之首了。
    不想再说下去了,浪费时间。
    class A
    {
    public:
        int i;    A() { i = 0; }
        A(const A& a) { i = a.i; }
        virtual ~A() { i = -1; }    void assign(const A& a);
    };void A::assign(const A& a)
    {
        this->~A();
    //    A();              // 你的代码
        new (this) A(a);  // 我的代码
    }void main()
    {
        A a, b;    b.i = 2;
        a.assign(b);
        printf("%d", a.i);
    }你根本都没编译运行过。
    我确认,我是正确的,不知别的编译器是怎样的,但是, vs2010 能证明我是正确的。

      

  28.   

    说话的时候不要自以为是。我的代码已经贴上来了,运行结果也可以告诉你:用A()输出结果是-1,用new (this) A(a)输出结果是2。
    如果你确认你是正确的,那么贴出你的代码和运行结果!
      

  29.   

    这个只是我在翻看C++ primier的时候发现的一个忽略的习题。觉得奇特,所以拿出来讨论讨论。并非我想走偏门路线,说实在的我也对此不是十分的了解和掌握。
      

  30.   

    这算不上什么偏门,所有需要自己进行内存分配的地方都是用这种方式实现的,而且这也是唯一的实现方式。几乎所有的容器类库和模版库,比如MFC、stl之类使用的都是这种方法,因为对于产品化的容器来说,如果不是自己做内存分配的话,那效率也实在太低了。
      

  31.   

    此贴尚未结贴。可惜我看的是C++ Primer Plus
      

  32.   

    如果觉得这个真的让你学习到了知识,那就弄一个电子C++ primier看看吧。
      

  33.   


    使用 new (this) A(a): 在VS2010中出现“error C2660: “operator new”: 函数不接受 2 个参数”
    在GCC中出现“
    <internal>: In member function `void A::assign(const A&)':
    <internal>:23: error: too many arguments to function `void* operator
       new(unsigned int)'
    testNew.cpp:23: error: at this point in file”请问怎样能编辑通过?是不是那里写错了?
      

  34.   


    解决问题了,xxd_qd的程序没有问题,结果与他说的一样,学习了