【问题标题】:Replace the default copy constructor with a template copy constructor用模板复制构造函数替换默认的复制构造函数
【发布时间】:2014-05-13 20:40:49
【问题描述】:

我有一个模板类 C。我想要这样一个模板复制构造函数,它会根据另一个类的大小调整数据数组的大小。

下面是一个简单的例子。它工作正常。但是,请注意Constructor 2Constructor 3 是如此相似,我想知道是否可以将它们合并为一个?

另外,如果我简单地删除Constructor 3,那么C<int> c3( c1 ) 将不会调用Constructor 2,而是会调用编译器添加的默认复制构造函数。这将导致内存分配不正确。

template<typename T>
class C
{
public:
    T* val; 
    int size; 
public:

    C( int s = 0 ) {
        cout << "Constructor 1" << endl; 
        size = s; 
        val = ( size ) ? new T[size] : nullptr; 
    } 

    template<class T2>
    C( const C<T2>& c2 ) {
        cout << "Constructor 2" << endl; 
        size = c2.size; 
        val = ( size ) ? new T[size] : nullptr; 
    } 

    C( const C<T>& c2 ) {
        cout << "Constructor 3" << endl; 
        size = c2.size; 
        val = ( size ) ? new T[size] : nullptr; 
    } 

    ~C() {
        cout << "~C()" << endl; 
        delete[] val; 
        val = nullptr; 
    }
};

int main(void)
{
    C<int>   c1( 5 );
    C<float> c2( c1 );  
    C<int>   c3( c1 ); 

    return 0;
}

上述函数的输出:

Constructor 1
Constructor 2
Constructor 3
~C()
~C()
~C()

【问题讨论】:

  • 您可以使用 C++11 中的构造函数委托,或执行此初始化的成员函数(助手)。
  • 假设您想对分配的内存做一些有用的事情,那么构造函数 2 将如何处理来自源类型的对象?
  • 你打算在那些构造函数中复制c2.val的元素吗?
  • @dyp 是的,我也想要数据。但我没有在上面的帖子中提到它。但这不是问题。
  • 您可以根据委托构造函数来实现构造函数 3。这是 C++11 中的新功能。

标签: c++ templates constructor


【解决方案1】:

替换

template<class T2>
C( const C<T2>& c2 ) {
    cout << "Constructor 2" << endl; 
    size = c2.size; 
    val = ( size ) ? new T[size] : nullptr; 
} 

C( const C<T>& c2 ) {
    cout << "Constructor 3" << endl; 
    size = c2.size; 
    val = ( size ) ? new T[size] : nullptr; 
} 

通过

template<class T2>
C( const C<T2>& c2, int dummy) {
    cout << "Constructor 2" << endl; 
    size = c2.size; 
    val = ( size ) ? new T[size] : nullptr; 
}

template<class T2>
C( const C<T2>& c2 ) : C(c2, 0) {}

C( const C<T>& c2 ) : C(c2, 0) {} 

更新

你可以使用:

C( int s = 0 ) {
    cout << "Constructor 1" << endl; 
    size = s; 
    val = ( size ) ? new T[size] : nullptr; 
} 

template<class T2>
C( const C<T2>& c2 ) : C(c2.size) {}

C( const C<T>& c2 ) : C(c2.size) {} 

并且不需要第二个构造函数。

【讨论】:

  • 没有那么优雅。然而,这似乎是解决这个问题的唯一方法。
  • 通常,您使用一个特殊的私有类作为虚拟对象的类型,并将该 ctor 设为私有。这可以防止重载问题(类的用户无意中调用了该 ctor)。
  • 看起来很像通过在签名中添加 int 来重载后缀 inc/dec 运算符的方式。就更新而言,这在这里有效;但是 OP 确实将这些称为复制构造函数,也许省略了执行实际复制或类型转换的代码,在这种情况下,公共代码中必须知道 T2。
  • @Apriori 我并没有完全按照您评论中最后一条声明的标题。
  • @R Sahu:假设您正在从C&lt;float&gt; 复制C&lt;int&gt;,并且复制/转换构造函数实际上复制(并在这种情况下转换)源容器中的元素。也就是说,如果您有一个 C&lt;float&gt; source; 包含 {1.2f, 3.9f, 5.5f} 并且您创建对象 C&lt;int&gt; dest(source); 您可能希望它具有值 {1, 3, 5} 因为包含的浮点数已被转换为整数。 OPs 代码只是分配要复制的空间,但从不复制。要执行转换,您需要知道要复制的类型,不能只复制字节。
【解决方案2】:

希望使用 C++11 委托构造函数来实现这一点。但是,由于模板参数是针对类还是针对构造函数的不明确性,这不可能以直接的方式进行。作为一种解决方法,可以将通用代码分解为辅助函数。

类似:

    template<class T2>
    C( const C<T2>& c2 ) {
        Copy<T2>(c2);
    } 

    C( const C<T>& c2 ) {
        Copy<T>(c2);
    }

private:
    template<class T2>
    void Copy( const C<T2>& c2 ) {
        cout << "Constructor 2" << endl; 
        size = c2.size; 
        val = ( size ) ? new T[size] : nullptr; 
    }

【讨论】:

  • 很确定第二个构造函数是委托给自己的。编辑:Yep, it is。有趣的是,clang 检测到并抛出错误,而 gcc segfaults。
  • @Praetorian:是的,你是对的。我试图弄清楚总体思路。但是,是的,它并没有像人们想要的那样解析模板参数。顺便说一句,在 VS 中,除非您将警告视为错误,否则您将获得“成功”构建。我用一些不同的东西更新了答案,不会改变第二个 ctor 的签名。
猜你喜欢
  • 2011-07-15
  • 1970-01-01
  • 2020-05-14
  • 2016-09-12
  • 1970-01-01
  • 1970-01-01
  • 2014-03-24
  • 2011-05-24
  • 1970-01-01
相关资源
最近更新 更多