C++ 复制构造函数是如何使用的,为什么它们很重要?

C++ 复制构造函数是如何使用的,为什么它们很重要?,c++,C++,什么是复制构造函数 我们为什么要使用它们?如果我们这样做,有必要调用析构函数吗 复制构造函数之所以重要,原因与常规构造函数相同,那就是正确初始化构造的对象。构造并不总是琐碎的,从何处获取数据以及以何种形式获取数据并不重要——相同类的其他对象或一组更简单的参数 所以,复制构造函数是用来解决初始化常量字段之类的问题的,但当您使用指针时,也可以用来决定所指资源的所有权。您可能希望共享或复制数据 什么是复制构造函数? 引用C++11标准,§12.8/2: 如果类X的非模板构造函数的第一个参数类型为X&,

什么是复制构造函数


我们为什么要使用它们?如果我们这样做,有必要调用析构函数吗

复制构造函数之所以重要,原因与常规构造函数相同,那就是正确初始化构造的对象。构造并不总是琐碎的,从何处获取数据以及以何种形式获取数据并不重要——相同类的其他对象或一组更简单的参数

所以,复制构造函数是用来解决初始化常量字段之类的问题的,但当您使用指针时,也可以用来决定所指资源的所有权。您可能希望共享或复制数据

什么是复制构造函数? 引用C++11标准,§12.8/2:

如果类
X
的非模板构造函数的第一个参数类型为
X&
const X&
,则该类的非模板构造函数是副本构造函数,
volatile X&
const volatile X&
,或者没有其他参数,或者没有其他所有参数 “有默认参数”

所以有4种不同的形式。其中最常用的是
X const&
形式。这也是隐式复制构造函数的形式,如果没有为类声明复制构造函数,则生成该构造函数(如果可能)

复制构造函数用于将对象复制到类的新实例。默认复制构造函数执行成员级复制,这与仅复制位不同,也比复制位更安全。具体而言,复制构造函数或移动构造函数在逻辑上用于复制初始化,即使用
=
符号的初始化

Some_type x = expression;
在某些情况下,编译器可以假设复制是复制构造函数所做的一切,而不管它实际做什么。逻辑上不必要的复制构造可以被删除,或者按照标准的说法,被省略。例如,如果上面的表达式是数字42,则可以使用该参数直接初始化
x
,而不是使用该参数来构造临时变量并将其复制或移动到
x

但是,即使这样做了,也不会使用复制构造函数,如果复制构造函数在优化之外会被使用,那么复制构造函数必须存在并且可以访问

C++11§12.2/1:

“即使临时对象的创建未经评估(第5条) 或以其他方式避免(12.8),应遵守所有语义限制,如同临时对象已被删除一样 已创建并随后销毁。”


有必要调用析构函数吗? Re“如果我们[使用复制构造函数],是否需要调用析构函数?”

一般不会

< > C++中的析构函数在对象超出范围时被自动调用,或者当它通过“代码>删除< /代码>被间接或直接销毁时被自动调用。唯一的例外是placement new,这是一个与复制构造函数无关的低级功能。虽然新的放置可能涉及复制构造


C++03和C++11复制构造函数之间的差异。 要理解C++03和C++11在副本构造函数方面的差异,您必须了解三个事实:

  • 如果未声明副本构造函数,则会在可能的情况下生成它。因此,默认情况下,每个类都有一个复制构造函数。就在那里

  • 访问与过载分辨率无关。
    重载解析在所有成员函数之间进行选择,无论它们是否可访问。然后检查访问权限。在这一点上,您可能会收到一条关于调用不可访问函数的错误消息,尽管期望重载解析最好只能从可访问函数中选择

  • 普通函数(或只是函数)比具有相同签名的函数模板的实例化更匹配

下面是一个重载解析的示例,它选择了一个
private
成员函数,尽管可以调用一个
public
函数:

文件[access\u vs\u overload\u resolution.cpp]

下面是一个普通函数胜过模板实例化的示例:

文件[function\u vs\u template.cpp]

使用旧的g++编译:

[H:\dev\test\copy_construction] > \bin\MinGW_3_1\bin\g++ --version | find "++" g++ (GCC) 3.2.3 (mingw special 20030504-1) [H:\dev\test\copy_construction] > \bin\MinGW_3_1\bin\g++ -std=c++98 -pedantic template_versus_cc.cpp template_versus_cc.cpp: In function `int main()': template_versus_cc.cpp:4: `S::S(const S&)' is private template_versus_cc.cpp:19: within this context [H:\dev\test\copy_construction] > _ [H:\dev\test\copy\u构造] >\bin\MinGW_3_1\bin\g++--version | find“++” g++(GCC)3.2.3(mingw special 20030504-1) [H:\dev\test\copy\u构造] >\bin\MinGW\u 3\u 1\bin\g++-std=c++98-学究式模板与cc.cpp 函数“int main()”中的模板\u与\cc.cpp: 模板与cc.cpp:4:'S::S(const S&')是私有的 模板与cc.cpp:19:在此上下文中 [H:\dev\test\copy\u构造] > _ 根据C++03/C++98规则,编译器应该在第18行和第19行标记两个副本初始化,但只标记后者,在这方面表现为C++11编译器

<>这也是现代的G+4.4.2的原理以及Visual C++ 12。但是一个合格的C++03编译器必须诊断这两种初始化


Scott Meyers引用了两位C++闲人作为资料来源。不幸的是,这篇文章给人的印象是:(1)这都是关于C++11中的通用引用模板参数的,(2)g++中没有bug。如上所示,前者是错误的,而后者则是正确的。有一个bug,但随着标准的发展,使用C++11,g++行为现在符合要求了…

为什么不在发布之前使用google?C中没有复制构造函数。那么为什么要标记这个问题[C]?你可能应该得到你自己的答案。副本当前选择了一个不正确的答案作为解决方案。此外,复制构造函数的概念在C++11中发生了微妙的变化,而重复的问题来自2010年。投票重开。@干杯,我不觉得这样更好吗
using One = char[1];
using Two = char[2];

auto foo( char const* ) -> One&;
auto foo( char const (&)[10] ) -> Two&;

auto bar( char const* ) -> One&;

template< int n >
auto bar( char const (&)[n] ) -> Two&;

#include <iostream>
auto main() -> int
{
    using namespace std;
    //cout << sizeof( foo( "Blah blah" ) ) << endl;       //! Ambiguous
    cout << sizeof( bar( "Blah blah" ) ) << endl;       // "1"
}
class S
{
private:
    S( S const& );  // No such.

public:
    S() {}

    template< class T >
    S( T& ) {}
};

int main()
{
    S sm;
    S const sc;

    S s1( sm );     // OK in C++11, template is better match.
    S s2( sc );     //! Line 19. Copy constructor is selected, inaccessible.
}
[H:\dev\test\copy_construction] > \bin\MinGW_3_1\bin\g++ --version | find "++" g++ (GCC) 3.2.3 (mingw special 20030504-1) [H:\dev\test\copy_construction] > \bin\MinGW_3_1\bin\g++ -std=c++98 -pedantic template_versus_cc.cpp template_versus_cc.cpp: In function `int main()': template_versus_cc.cpp:4: `S::S(const S&)' is private template_versus_cc.cpp:19: within this context [H:\dev\test\copy_construction] > _