我遇到了复制构造函数错误,但不知道我对这个错误的想法是否正确

I've met an copy constructor error, but don't know if my thought about this error is correct

我正在编写一个名为 StackGuard 的 unique_ptr-like class,并尝试创建两个复制构造函数:

template<typename T>    
class StackGuard{
  T* thePtr;   //To store the raw pointer.
               //something here...
  StackGuard(StackGuard<T>& newPtr) throw();
  StackGuard(StackGuard<T> newPtr) throw();  //I know this is not the right way
              //something here...
};

template<typename T>
StackGuard<T>::StackGuard(StackGuard<T>& newPtr) throw(){
    thePtr = newPtr.thePtr;
    newPtr.thePtr = NULL;
}

template<typename T>
StackGuard<T>::StackGuard(StackGuard<T> newPtr) throw(){
    thePtr = newPtr.thePtr;
    newPtr.thePtr = NULL;
}

但是没用。编译器说

error: invalid constructor; you probably meant ‘StackGuard<T> (const StackGuard<T>&)’
     StackGuard(StackGuard<T> newPtr) throw();
                                            ^
error: prototype for ‘StackGuard<T>::StackGuard(StackGuard<T>)’ 
does not match any in class ‘StackGuard<T>’
  StackGuard<T>::StackGuard(StackGuard<T> newPtr) throw(){
  ^
error: candidates are: StackGuard<T>::StackGuard(const StackGuard<T>&)
  StackGuard<T>::StackGuard(const StackGuard<T>& newPtr) throw(){
  ^
error:                 StackGuard<T>::StackGuard(T*)
  StackGuard<T>::StackGuard(T* guarded = NULL) throw() {

我想到了这个错误,但不知道对不对。

我的想法是:

传值拷贝构造函数需要使用拷贝构造函数来拷贝参数,在这种情况下,它会递归调用自己,导致无限调用。

我也想知道,为什么编译器会给出 "does not match any in class" 错误,因为它有一个匹配项。

您关于复制构造函数必须递归调用自身的假设是正确的。因此,标准不允许按值声明复制构造函数。这意味着只有第二个版本是合法的。

另一个构造函数是合法的。但是,您通常应该通过 const 引用来声明复制构造函数。构造函数不应修改其输入,因此您应该让编译器为您强制执行保证。使用 const 引用还可以让您复制 const 对象,否则您无法做到这一点。

来自[class.copy]:

A declaration of a constructor for a class X is ill-formed if its first parameter is of type (optionally cv-qualified) X and either there are no other parameters or else all other parameters have default arguments. A member function template is never instantiated to produce such a constructor signature.

您的构造函数 StackGuard(StackGuard<T> ) 格式错误。这里的问题与递归无关:这样的构造函数会导致歧义。考虑等价物:

void foo(int ) { }
void foo(int& ) { }

int i;
foo(i); // error: ambiguous

如果允许这样的构造函数,这个冒名顶替的复制构造函数和真正的(隐式或显式)复制构造函数之间总会有歧义。

此外,"unique-ptr like" 不建议我复制。您需要编写一个移动构造函数。如果您无法访问 C++11,则需要查看 auto_ptr 的实现方式并从那里复制。