【问题标题】:Why does conversion operator call copy constructor twice when equivalent function calls it only once?当等效函数只调用一次时,为什么转换运算符调用复制构造函数两次?
【发布时间】:2019-11-07 14:45:17
【问题描述】:

我在 Visual Studio 2017 中运行。我的程序定义了一个带有转换运算符的类,并定义了一个等效的转换函数。

#include <iostream>
#include <string>

template<class T, class U>
struct A
{
    A();
   ~A() { std::cout << "In A destructor\n"; delete n; }
    A(T i);
    A(const A& a);
    operator A<U,T>();
    T* n;
};

template<class T, class U>
A<T,U>::A()
{
    n = new T;
   *n = 0;
}

template<class T, class U>
A<T,U>::A(T i)
{
    n = new T;
   *n = i;
}

template<class T, class U>
A<T,U>::A(const A& a)
{
    std::cout << "In A copy constructor\n";
    n = new T;
   *n = *(a.n);
}

template<class T, class U>
A<T,U>::operator A<U,T>()
{
    A<U,T> aut;
    *(aut.n) = static_cast<U>(*n);
    return aut;
}

template<class T, class U>
std::ostream& operator<<(std::ostream& os, A<T,U>& a)
{
    os << *(a.n);
    return os;
}

template<class T, class U>
A<U,T> convert(A<T,U>& a)
{
    A<U,T> c;
   *(c.n) = static_cast<U>(*(a.n));
    return c;
}

int main()
{
    std::string s;

    A<int, unsigned int> a1(-1);
    std::cout << a1 << "\n";

    A<unsigned int, int> a2 = A<unsigned int, int>(a1);
    std::cout << a2 << "\n";

    A<unsigned int, int> a3 = convert(a1);
    std::cout << a3 << "\n";

    std::cout << "Press ENTER to exit\n";
    getline(std::cin, s);
}

我没有优化编译时的输出是

-1
In A copy constructor
In A destructor
In A copy constructor
In A destructor
4294967295
In A copy constructor
In A destructor
4294967295
Press ENTER to exit

复制构造函数在程序调用转换运算符后被调用两次,但在它调用函数convert() 后只调用一次,该函数执行相同的操作。似乎在对转换运算符的调用中,程序正在创建一个临时对象,函数convert() 不会导致生成该对象。为什么调用转换运算符后程序调用拷贝构造函数的次数和调用convert()后程序调用拷贝构造函数的次数会有差异?

【问题讨论】:

  • 我无法重现。这似乎取决于编译器及其优化选项。
  • 我怀疑这是因为A&lt;unsigned int, int&gt;(a1) 不是使用转换运算符的显式转换,而是在 隐式转换之后创建对象。 (但我在标准中找不到任何关于它的信息,所以它可能不是答案。)

标签: c++ type-conversion


【解决方案1】:

定义

A<unsigned int, int> a2 = A<unsigned int, int>(a1);

真的

A<unsigned int, int> a2 = A<unsigned int, int>(a1.operator A<unsigned int, int>());

相当于

A<unsigned int, int> temporary_compiler_generated_object = a1.operator A<unsigned int, int>();
A<unsigned int, int> a2 = temporary_compiler_generated_object;

这里需要调用临时对象的复制构造函数以及a2

【讨论】:

  • 为什么函数convert()不以完全相同的方式创建第二个临时对象?
  • @TRPh 当您使用 convert 时,您正在通过复制构造 (a3) 创建单个对象。当您创建 a2 时,您通过复制构造隐式创建 两个 对象。
  • 显然。但为什么呢?
  • @TRPh A&lt;unsigned int, int&gt;(a1) 不是演员表,它会创建一个临时对象。这个临时对象将被复制初始化。 然后您还可以使用临时对象的复制初始化创建a2 对象。
猜你喜欢
  • 2022-07-05
  • 2013-12-11
  • 1970-01-01
  • 1970-01-01
  • 2015-04-28
  • 1970-01-01
  • 1970-01-01
  • 2020-06-29
相关资源
最近更新 更多