【问题标题】:Template functions: default construction without copy-constructing in C++模板函数:C++ 中没有复制构造函数的默认构造函数
【发布时间】:2011-07-15 06:03:25
【问题描述】:

考虑

struct C { 
   C()            { printf("C::C()\n"          ); }
   C(int)         { printf("C::C(int)\n"       ); }
   C( const C& )  { printf("copy-constructed\n"); }
};

还有一个模板函数

template< typename T > void foo(){
    // default-construct a temporary variable of type T
    // this is what the question is about.
    T t1;       // will be uninitialized for e.g. int, float, ...
    T t2 = T(); // will call default constructor, then copy constructor... :(
    T t3();     // deception: this is a local function declaration :(
}

int main(){
    foo<int>();
    foo<C  >();
}

查看t1,当T为e.g.时,它不会被初始化。 int。另一方面,t2 将从一个默认构造的临时对象复制构造。

问题:除了 template-fu 之外,C++ 中是否可以默认构造一个泛型变量?

【问题讨论】:

  • 对于那些认为...我以前见过这种问题的人,今天...他们是对的。但是这个问题的这个方面仍然没有答案。
  • @xtofl: template-fu 是什么?
  • @Nawaz:功夫的C++版本。
  • @Ben:酷。这个术语在 C++ 社区中足够流行吗?还是新发明的?
  • @Nawaz : [anything]-fu 很受欢迎。多见于“My python-fu is not strong enough”之类的句子中。

标签: c++ templates copy-constructor default-constructor


【解决方案1】:

您可以使用以下技巧,使用本地类:

template <typename T> void foo() {
    struct THolder {
        T obj;
        THolder() : obj() { } // value-initialize obj
    };

    THolder t1; // t1.obj is value-initialized
}

我想我是从另一个 Stack Overflow 问题的答案中了解到这个技巧的,但目前我找不到那个问题。

或者,您可以使用boost::value_initialized&lt;T&gt; 类模板,它基本上做同样的事情,具有更大的灵活性和一致性,并为有问题的编译器提供解决方法。

在 C++0x 中,这要容易得多:您可以使用空的初始化列表:

T obj{}; // obj is value-initialized

(据我所知,只有 gcc 4.5+ 支持 C++0x 初始化列表。Clang 和 Visual C++ 尚不支持它们。)

【讨论】:

  • 我想你可以从我对上述问题的回答中读到它:) stackoverflow.com/questions/5300602/…
  • @xtofl:啊,所以你已经知道这个技巧了。据我所知,这是 C++03 的实现方式(在 C++0x 中,您可以使用初始化列表)。 [今天早上我没有看到这个问题;这个技巧是去年某个时候提到的]
  • 我在等有人提到 C++0x。你能举个例子吗?
  • @xtofl:我已经添加了如何使用空的 C++0x 初始化程序列表来完成此操作。
  • @xtofl:在 C++0x 中,这应该是简单的 X x{}; - 但是,此时似乎某些编译器可以(显然是错误的?!)调用构造函数重载,采用 initializer_list如果可用(请参阅ideone.com/Il93E 并注释掉要比较的重载)。
【解决方案2】:

如果你不关心拷贝构造函数必须存在的事实,只是想阻止它被调用:

别担心:不会的。在这种情况下,复制构造函数调用将被省略。始终可靠 - 即使您在禁用优化的情况下进行编译 (-O0)。

【讨论】:

  • “始终、可靠”——在每个 C++ 编译器上,甚至在无法访问复制构造函数的情况下?
  • @Ben 第一部分:关于所有这些。第二部分:我在回答的第一句话中已经解决了这个问题。
  • “始终可靠”是一个很高的要求!
  • @Nawaz 这段代码是一个固定的习惯用法,标准明确提到编译器可以对此进行优化。我有理由相信,即使不是最近的编译器也能做正确的事情。也就是说,我说的是现实世界。当然,任何人都可以构建一个符合标准的编译器来违反这一声明。但这并不重要。
  • 虽然编译器消除了不必要的副本,但它仍然需要一个可访问的副本构造函数。
【解决方案3】:

你真正的问题是什么? t1 实例调用默认构造函数。

【讨论】:

  • 是的,如果 T 是一个类类型。如果T 是,例如int,那么t1 将保持未初始化状态。
  • 好吧......它不适用于int。我会尝试重新提出问题。
  • @James:但练习的意义何在?这是一个琐事问题吗?是否尝试自动初始化变量?
  • 它正在尝试编写适用于类和内置类型的通用代码,并且不会产生任何开销。
【解决方案4】:

T t2 = T(); // 将调用默认构造函数,然后复制构造函数... :(

不在我的编译器 (VC2008) 上。对我来说输出是......

C::C()
C::C()

这是我期望它做的。我错过了什么吗?

【讨论】:

  • 那是因为可以省略对复制构造函数的调用。如果复制构造函数不可访问或不可调用,则 T t2 = T(); 将不起作用。
  • 好的,我现在明白了。也许问题中的评论需要阅读“//需要可访问的复制构造函数:(”
猜你喜欢
  • 1970-01-01
  • 2020-05-14
  • 1970-01-01
  • 1970-01-01
  • 2011-03-27
  • 2015-07-24
  • 1970-01-01
  • 2020-05-19
  • 2016-03-01
相关资源
最近更新 更多