1

我有一个 A 类,它在其构造函数中为整数(由类成员说 _pPtrMem 指向)动态分配内存,并在析构函数中释放相同的内存。为了避免浅拷贝,我重载了赋值运算符和拷贝构造函数。赋值运算符重载的广泛使用方式如下:

A& operator = (const A & iToAssign)
{
  if (this == & iToAssign)  // Check for self assignment
    return *this;
  int * pTemp = new int(*(iToAssign._pPtrMem)); // Allocate new memory with same value
  if (pTemp)
  {
    delete _pPtrMem;  // Delete the old memory
    _pPtrMem = pTemp; // Assign the newly allocated memory
  }
  return *this;   // Return the reference to object for chaining(a = b = c)
}

另一种实现相同的方法可能是

A& operator = (const A & iToAssign)
{
  *_pPtrMem= *(iToAssign._pPtrMem); // Just copy the values
  return *this;   
}

既然第二个版本比较简单和快速(没有释放,内存分配),为什么它没有被广泛使用?有什么我无法解决的问题吗?

此外,我们从赋值运算符中返回一个相同类型的对象,用于链接(a = b = c)......所以不是返回*this而是返回iToAssign对象,因为两个对象现在应该相等?

4

5 回答 5

6

通常,实现复制赋值运算符的最佳方式是swap()为您的类提供一个函数(或使用标准函数,如果它可以满足您的需要),然后通过复制构造函数实现复制赋值运算符:

A& A::operator= (A iToAssign)  // note pass by value here - will invoke copy constructor
{
  iToAssign.swap(*this);
  return *this;
}
// void swap(A& other) throws() // C++03
void A::swap(A& other) noexcept
{
    std::swap(_pPtrMem, other._pPtrMem);
}

这可以确保您的复制赋值运算符和复制构造函数永远不会发生分歧(也就是说,不会发生您更改一个而忘记更改另一个的情况)。

于 2013-03-12T08:00:21.340 回答
2

不,您的实施没有问题。但是动态分配一个整数至少是非常特别的。

这种实现并没有被广泛使用,因为没有人在空闲存储区分配一个整数。您通常将动态分配的内存用于在编译时可变长度未知的数组。在这种情况下,大多数时候只使用 std::vector 是个好主意。

不,这不好,返回一个不同的对象。身份不等于平等:

T a, b, d;
T& c = a = b;
c = d; // should change a, not b 

你会期望第三行改变 b 吗?

或者更好的事件示例:

T a;
T& b = a = T();

这将导致一个悬空引用,引用一个临时的和被破坏的对象。

于 2013-03-12T08:05:04.917 回答
1

第一个版本用于_pPtrMem指向某些基本类型的指针,例如动态分配的数组。如果指针指向具有正确实现的赋值运算符的单个对象,则第二个版本将做得同样好。但在那种情况下,我认为您根本不需要使用指针。

于 2013-03-12T07:59:48.337 回答
0

在第二种情况下,如果_pPtrMem最初未分配,则该行

*_pPtrMem= *(iToAssign._pPtrMem); // Just copy the values

导致分配到无效的内存位置(可能是分段错误)。这只有_pPtrMem在此调用之前已分配内存时才有效。

于 2013-03-12T07:59:05.543 回答
0

在这种情况下,第二种实现方式要好得多。但是在对象中使用动态的通常原因是因为大小可能会有所不同。(另一个原因是因为您想要浅拷贝的引用语义。)在这种情况下,最简单的解决方案使用您的第一个分配(无需测试自分配)。根据对象的不同,如果新值适合,可以考虑重用已经存在的内存;它在一定程度上增加了复杂性(因为您必须测试它是否适合,如果不适合,仍然进行分配/复制/删除),但在某些情况下它可以提高性能。

于 2013-03-12T09:45:05.867 回答