如何强制编译器使用显式复制构造函数? [英] How to force the compiler to use explicit copy constructor?

查看:193
本文介绍了如何强制编译器使用显式复制构造函数?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我写了一个小测试程序,其中包含一个样例类,还包含自定义构造函数,析构函数,复制构造函数和赋值运算符。当我意识到复制构造函数根本没有被调用时,我感到惊讶,即使我实现了函数的返回值类和 Object o1;对象o2(o1);



innerclass.hpp:

  #include< iostream> 

class OuterClass
{
public:
OuterClass()
{
std :: cout< OuterClass Constructor< std :: endl;
}
〜OuterClass()
{
std :: cout< OuterClass Destructor< std :: endl;
}
OuterClass(const OuterClass& rhs)
{
std :: cout< OuterClass Copy< std :: endl;
}
OuterClass& operator =(const OuterClass& rhs)
{
std :: cout< OuterClass Assignment< std :: endl;
}

class InnerClass
{
public:
InnerClass():m_int(0)
{
std :: cout < InnerClass Constructor< std :: endl;
}
InnerClass(const InnerClass& rhs):m_int(rhs.m_int)
{
std :: cout< InnerClass Copy< std :: endl;
}
InnerClass& operator =(const InnerClass& rhs)
{
std :: cout< InnerClass Assignment< std :: endl;
m_int = rhs.m_int;
return * this;
}
〜InnerClass()
{
std :: cout< InnerClass Destructor< std :: endl;
}
void sayHello()
{
std :: cout< 你好! << std :: endl;
}

private:
int m_int;
};

InnerClass innerClass()
{
InnerClass ic;
std :: cout<< innerClass()method< std :: endl;
return ic;
}
};

innerclass.cpp:

  #includeinnerclass.hpp

int main(void)
{
std :: cout< std :: endl< 1st try:<< std :: endl;


OuterClass oc;
OuterClass oc2(oc);
oc.innerClass()。sayHello();

std :: cout<< std :: endl< 2nd try:<< std :: endl;

OuterClass :: InnerClass ic(oc.innerClass());
ic = oc.innerClass();
}

输出:

 第一次尝试:
OuterClass构造方法
OuterClass复制
InnerClass构造方法
innerClass()方法
Hello!
InnerClass析构函数

第二次尝试:
InnerClass构造函数
innerClass()方法
InnerClass构造函数
innerClass()方法
InnerClass赋值
InnerClass析构函数
InnerClass析构函数
OuterClass析构函数
OuterClass析构函数


$ b b

经过一些研究,我读到,不能保证编译器将使用明确定义的复制构造函数。我不明白这个行为。为什么复制构造函数甚至存在,如果我们不知道它被调用?编译器如何决定是否使用它?



或者,更好的办法是强制编译器使用自定义的拷贝构造函数?

解决方案

为了完整性,其他答案,标准允许编译器在某些情况下省略复制构造函数(其他答案称为返回值优化或优化 - RVO / NRVO):


12.8复制类对象,第15段(C ++ 98)



每当使用复制构造函数复制临时类对象,并且此对象和副本具有相同的cv无限定类型时,允许实现将原始和副本作为两种不同的方式引用相同的对象,并且根本不执行副本,即使类复制构造函数或析构函数具有副作用。对于具有类返回类型的函数,如果return语句中的表达式是本地对象的名称,并且本地对象的cv非限定类型与函数返回类型相同,则允许实现省略创建临时对象保持函数返回值,即使类的复制构造函数或析构函数有副作用。在这些情况下,对象将在较晚的时候销毁原始和副本,而不进行优化。


因此在你的 innerClass()方法中,你可能认为在返回时调用的拷贝构造函数被允许优化:

  InnerClass innerClass(){
InnerClass ic;
std :: cout<< innerClass()method< std :: endl;
return ic; //这可能不调用copy ctor
}


I wrote a small test program with a sample class containing also self-defined constructor, destructor, copy constructor and assignment operator. I was surprised when I realized that the copy constructor was not called at all, even though I implemented functions with return values of my class and lines like Object o1; Object o2(o1);

innerclass.hpp:

#include <iostream>

class OuterClass
{
public:
OuterClass()
{
	std::cout << "OuterClass Constructor" << std::endl;
}
~OuterClass()
{
	std::cout << "OuterClass Destructor" << std::endl;
}
OuterClass(const OuterClass & rhs)
{
	std::cout << "OuterClass Copy" << std::endl;
}
OuterClass & operator=(const OuterClass & rhs)
{
	std::cout << "OuterClass Assignment" << std::endl;
}

class InnerClass
{
public:
	InnerClass() : m_int(0)
	{
		std::cout << "InnerClass Constructor" << std::endl;
	}
	InnerClass(const InnerClass & rhs) : m_int(rhs.m_int)
	{
		std::cout << "InnerClass Copy" << std::endl;
	}
	InnerClass & operator=(const InnerClass & rhs)
	{
		std::cout << "InnerClass Assignment" << std::endl;
		m_int = rhs.m_int;
		return *this;
	}
	~InnerClass()
	{
		std::cout << "InnerClass Destructor" << std::endl;
	}
	void sayHello()
	{
		std::cout << "Hello!" << std::endl;
	}

private:
	int m_int;
};

InnerClass innerClass()
{
	InnerClass ic;
	std::cout << "innerClass() method" << std::endl;
	return ic;
}
};

innerclass.cpp:

#include "innerclass.hpp"

int main(void)
{
std::cout << std::endl << "1st try:" << std::endl;


OuterClass oc;
OuterClass oc2(oc);
oc.innerClass().sayHello();

std::cout << std::endl << "2nd try:" << std::endl;

OuterClass::InnerClass ic(oc.innerClass());
ic = oc.innerClass();
}

Output:

 1st try:
 OuterClass Constructor
 OuterClass Copy
 InnerClass Constructor
 innerClass() method
 Hello!
 InnerClass Destructor

 2nd try:
 InnerClass Constructor
 innerClass() method
 InnerClass Constructor
 innerClass() method
 InnerClass Assignment
 InnerClass Destructor
 InnerClass Destructor
 OuterClass Destructor
 OuterClass Destructor

After some research I read that there is no guarantee that the compiler will use the explicitely defined copy constructor. I do not understand this behavior. Why does the copy constructor even exist then, if we do not know that it is called? How does the compiler decide if it uses it?

Or, even better, is there a way to force the compiler to use the self-defined copy constructor?

解决方案

Just for completeness with the other answers, the standard allows the compiler to omit the copy constructor in certain situations (what other answers refer to as "Return Value Optimization" or "Named Return Value Optimization" - RVO/NRVO):

12.8 Copying class objects, paragraph 15 (C++98)

Whenever a temporary class object is copied using a copy constructor, and this object and the copy have the same cv-unqualified type, an implementation is permitted to treat the original and the copy as two different ways of referring to the same object and not perform a copy at all, even if the class copy constructor or destructor have side effects. For a function with a class return type, if the expression in the return statement is the name of a local object, and the cv-unqualified type of the local object is the same as the function return type, an implementation is permitted to omit creating the temporary object to hold the function return value, even if the class copy constructor or destructor has side effects. In these cases, the object is destroyed at the later of times when the original and the copy would have been destroyed without the optimization.

So in your innerClass() method, the copy constructor you might think would be called at the return is permitted to be optimized away:

InnerClass innerClass() {
    InnerClass ic;
    std::cout << "innerClass() method" << std::endl;
    return ic;    // this might not call copy ctor
}

这篇关于如何强制编译器使用显式复制构造函数?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆