2

我正在寻找这样的语法:

class Hugo
{
    Hugo();
    explicit Hugo( const Hugo& hugo );

    Hugo GetRandomHugo()
    {
        Hugo hugo;
        hugo.value = rand();
                                  // this would fail:
                                  //    return hugo;

        return Hugo(hugo);        // explicit copy!!
    }
};

换句话说:我正在寻找一种显式的复制语法,以允许方法返回一个副本,即使我的复制构造函数是显式的。

我正在使用 GCC 4.4.5。

非常感谢,

查理

4

3 回答 3

5

You can't : a return by value is an implicit copy construction. Here, the return attempts to implicitly copy your explicitly copy-constructed temporary.

From 8.5/12 :

The initialization that occurs in argument passing, function return, throwing an exception (15.1), handling an exception (15.3), and brace-enclosed initializer lists (8.5.1) is called copy-initialization and is equivalent to the form :

T x = a;

于 2010-11-26T13:23:36.130 回答
3

HugoCopy您可以通过使用如下的显式类来解决此问题

class HugoCopy;
class Hugo {
public:
    Hugo() { ... }  
    Hugo(HugoCopy const&);
    explicit Hugo(Hugo const&) { ... }
};

struct HugoCopy { 
    HugoCopy(Hugo const& hugo) 
      :hugo(hugo)
    { }

    Hugo const& hugo;
};

Hugo::Hugo(HugoCopy const&) { ... }

现在适用以下语义

Hugo a;
Hugo b = a; // forbidden
Hugo c(a); // allowed
Hugo d = HugoCopy(a); // allowed

Hugo f() {
  Hugo a;
  return a; // forbidden
  return HugoCopy(a); // allowed
}

或者,您可以使用转换功能

class Hugo {
public:
    Hugo() { ... }  
    explicit Hugo(Hugo const&) { ... }
};

struct HugoCopy { 
    HugoCopy(Hugo const& hugo) 
      :hugo(hugo)
    { }
    operator Hugo const&() { return hugo; }

private:
    Hugo const& hugo;
};

这依赖于 C++ 语言的一个微妙角落。所以如果你使用它,你最好知道你在做什么或者你不这样做:它首先调用 HugoCopy 上的转换函数(或者在第一种情况下, 的构造函数Hugo)来获取Hugo/ Hugo const&,然后它直接Hugo用该对象初始化目标Hugo对象。GCC 不喜欢该代码,但 Clang 和 Comeau/EDG 根据上述语义接受它。

于 2010-11-26T13:45:28.807 回答
1
return Hugo(hugo); 

这只是在返回之前创建了一个额外的副本。实际的 return 语句然后获取该副本并再次复制它复制它。复制构造函数的全部意义在于它可以隐式使用,只要我们或编译器需要复制一个对象。

如果你想要一个显式的语法,你可以在类中添加一个Clone()orCopy()函数,但它不能替换复制构造函数。

每次编译器需要复制一个对象时(例如,当通过值作为函数参数传递它时,或者从函数返回它时),它需要创建一个对象的副本。您无法为编译器执行此操作,因为您看不到调用者和被调用者之间的“转换”代码。您可以在被调用函数内部或外部复制对象,但您无法从被调用者的主体复制到调用者。只有编译器才能做到这一点,为了做到这一点,它需要能够随意复制对象——这是通过复制构造函数完成的。

于 2010-11-26T13:42:32.533 回答