C++ 中临时对象的陷阱

来源:互联网 发布:怎么作图软件下载 编辑:程序博客网 时间:2024/05/02 06:23

 

在问题叙述之前,我们先来看一段代码。

class MyString
{

public:
  char* GetBuffer() const
  {
    return m_pBuffer;
  }
private:
  void CopyContent(const char* pSrc)
  {
    m_pBuffer = new char [strlen(pSrc) + 1];
    strcpy(m_pBuffer,pSrc);
  }

public:
  MyString() : m_pBuffer(0)
  {

  }
  MyString(const char* pSrc) : m_pBuffer(0)
  {
    CopyContent(pSrc);
  }
  MyString(const MyString& src) : m_pBuffer(0)
  {
    char* p = src.GetBuffer();
    CopyContent(p);
  }

  ~MyString()
  {
    if(m_pBuffer)
    {
      delete [] m_pBuffer;
    }
  }

public:

  MyString& operator = (const MyString& src)
  {
    if(this != &src)
    {
      char* newdata = new char[strlen(src.GetBuffer()) + 1];
      if(m_pBuffer)
        delete [] m_pBuffer;
      m_pBuffer = newdata;
    }
    strcpy(m_pBuffer,src.GetBuffer());
    return *this;
  }

  MyString& operator += (const MyString& src)
  {
    size_t newsize = 0;
    newsize = strlen(m_pBuffer) + strlen(src.GetBuffer()) + 1;
   
    char* newdata = new char[newsize];
    strcpy(newdata,m_pBuffer);
    strcat(newdata,src.GetBuffer());
    delete [] m_pBuffer;
    m_pBuffer = newdata;

    return *this;
  }

  MyString& operator += (const char* src)
  {
    size_t newsize = 0;
    newsize = strlen(m_pBuffer) + strlen(src) + 1;

    char* newdata = new char[newsize];
    strcpy(newdata,m_pBuffer);
    strcat(newdata,src);
    delete [] m_pBuffer;
    m_pBuffer = newdata;

    return *this;
  }

  friend MyString operator + (const MyString& src1, const MyString& src2)
  {
    MyString res = src1;
    res += src2;
    return res;
  }

  friend MyString operator + (const char* src1, const MyString& src2)
  {
    MyString res = src1;
    res += src2;
    return res;
  }

  friend MyString operator + (const MyString& src1, const char* src2)
  {
    MyString res = src1;
    res += src2;
    return res;
  }
 
  operator char* ()
  {
    return GetBuffer();
  }
 
private:
  char* m_pBuffer;
};

int _tmain(int argc, _TCHAR* argv[])
{
 
  MyString a("abc");
  MyString b("def");
  MyString T = a + b; //方法1

  MyString K;
  K = a + b; //方法2

  //方法1,方法2那个更有效率呢?


  char* pTemp = 0;
  pTemp = (char*)(MyString("123") + MyString("456"));

  //....

 //访问pTemp,怎么有地址,却没有内容呢?

 return 0;

}

大家可以单步调试一下,你就会发现一些有趣的现象。原来这一切都是编译器在搞的鬼。

在写C++代码时,关于临时对象的问题,有几点是必须要注意的。

1 C++标准允许编译器来定义临时对象。对于大多数流行的编译器来说,

  如果有下列的表达式:

 T  a, b;

  T c = a + b; (1)

 而其中的加法定义为:

  T operator + (const T&, const  T &);

那么1 式实现就不会有临时对象的产生。

然而 ,意义相等的赋值语句,就不能够忽略临时对象的产生,这点可以从上面的代码中得以验证。

 T c;

 c = a + b;

展开成C++伪代码是:

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

 T temp;

 temp.operator + (a, b);

c.operator = (temp);

temp.T::~T();

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

2 临时对象的被摧毁,应该是对完整表达式求值过程中最后一个步骤。

(条件是:该表达式会导致临时对象的产生)

 这点可以从pTemp中得以验证。

3 凡含有表达式执行结果的临时对象,应该保留到对象的初始化完成为止。

正是因为有临时对象的存在,会导致程序执行比较没有效率。这一点从与FORTRAN-77的测试对比可以得出。

但是也不必过于担心,因为现在的编译器都会通过反聚合的方法来加以优化。

原创粉丝点击