【问题标题】:Copy constructor is not called for copy-initialization or optimized?复制构造函数不调用复制初始化或优化?
【发布时间】:2011-01-09 14:07:06
【问题描述】:

如果复制构造函数是private然后在

案例1:没有错误,编译器不关心复制构造函数是否在类中定义。

案例2:错误,复制构造函数是私有的,当它被public时,它被省略了。

如果构造函数是private,它会直接优化副本而不注意吗?

#include <string>
using std::string;

class T
{
    string s;
    T(const T &obj):s(obj.s){}
public:
    T(const string &str):s(str){}
};

int main()
{
    T a = ("Copy Initialization");     //Case: 1

    T b = T("Copy Initialization");    //Case: 2
}

【问题讨论】:

  • Case:1 中,您实际上并没有创建T 类型的临时对象。你怎么能分配它a,它的类型是T

标签: c++ visual-c++-2010


【解决方案1】:

案例 2 在 N3225 中低于 12.8/31:

一个程序是非良构的,如果 复制/移动构造函数或复制/移动 对象的赋值运算符是 隐含的 odr-used 和特殊的 成员函数不可访问。

仅仅因为复制 ctor 被省略并不意味着它没有被 odr 使用。 3.2/2:

一组候选者的成员 函数是 odr-used 如果它是 由重载决议选择时 从一个 潜在评估的表达。 [注意:这包括对命名的调用 功能 (5.2.2),操作员 重载(第 13 条),用户定义 转换 (12.3.2)、分配 放置新功能(5.3.4),如 以及非默认初始化 (8.5)。复制构造函数或移动 构造函数是 odr-used 即使 call 实际上被 执行。 ——尾注]

当然要注意,MSVC 完全符合 C++0x,因为 (a) C++0x 还不是标准,也没有最终确定; (b) 无论如何,MSVC 并没有实现所有最新的东西。但是这些东西与 C++03 相比并没有实质性的改变,所以我相当有信心这个解释仍然成立。

案例 1 也属于这种情况,除了在我检查过的两个 C++03 编译器上,它没有那么远,因为不可能从字符串文字转换为 T。我不会被打扰要检查 C++0x 中是否允许任何额外的转换序列,任何地方都可能有一个新子句:-)

对我来说,为什么 MSVC 允许案例 1 仍然是个谜,即使是公共复制 ctor。是否允许在严格的 C++03 模式下使用?

【讨论】:

  • 你确定。 G++ 和 Comeau 都给出了错误。也许第一行(如果显式调用字符串构造函数)相当于T a = T(string("Copy Initialization"));?
  • @UncleBens:我确定什么?我最初对案例1所说的事情完全错误,不知道我在想什么。 g++ 和 Comeau 拒绝案例 1,因为不存在转换序列(有一个带有两个隐式用户定义转换的假设序列,但这是不允许的),复制 ctor 不相关。将显式转​​换添加到string,然后它就变得相关了。
  • Case 1 确实与std::string str = "Copy Initialization" 非常相似;
  • @Dave18:重要的区别在于std::string 有一个const char* 构造函数,而T 没有。如果供应商(在这种情况下为 MS)有一个扩展来将该转换视为内置的,即使它是根据标准用户定义的,我也不会感到完全惊讶。为了“方便”,对于那些只为启用了该扩展的编译器编写代码的人来说是方便的,所以他们可以给他们的类一个string构造函数,而不是const char*构造函数。
【解决方案2】:

案例1:无错误,编译器不关心复制构造函数是否在类中定义。

T a = ("Copy Initialization"); should give an error 因为没有合适的构造函数可以将"const char [20]" 转换为"T"

您是说T a = std::string("Copy Initialization"); 吗?

它是否直接优化了副本而不注意到构造函数是否被私有化?

不,它不能。编译器通常在代码优化阶段之前执行句法和语义分析。

【讨论】:

  • @Prasoon 在 c++0x 编译器上没有这样的 const char [20]T,因为进行了隐式类型转换。
  • @Prason:我真的很怀疑,请尝试确保使用实际的 c++0x 编译器 :)
  • @Dave18:C++0x 与 C++03 到底有什么不同,以允许在不显式转换为 std::string 的情况下实现这一点?
  • @Steve 不会有,但以防万一我在 MSVC++ 2010 上。
  • @Dave18:案例 1 需要两个用户定义的转换:首先从字符串文字 (const char [20]) 到 std::string,然后从 std::stringT。编译器无法推断出这样的转换序列,因为它可以/可能在转换序列中最多使用一个用户定义的转换。
猜你喜欢
  • 1970-01-01
  • 2011-09-04
  • 1970-01-01
  • 2018-03-02
  • 2015-06-09
  • 2023-03-05
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多