• Graphics and multimedia
  • Language Features
  • Unix/Linux programming
  • Source Code
  • Standard Library
  • Tips and Tricks
  • Tools and Libraries
  • Windows API
  • Copy constructors, assignment operators,

Copy constructors, assignment operators, and exception safe assignment

*

  • C++ Classes and Objects
  • C++ Polymorphism
  • C++ Inheritance
  • C++ Abstraction
  • C++ Encapsulation
  • C++ OOPs Interview Questions
  • C++ OOPs MCQ
  • C++ Interview Questions
  • C++ Function Overloading
  • C++ Programs
  • C++ Preprocessor
  • C++ Templates

The Rule of Five in C++

  • Rule Of Three in C++
  • Virtual Function in C++
  • real() function in C++
  • Order of Evaluation in C++17
  • Output in C++
  • std::all_of() in C++
  • Nested Classes in C++
  • multimap size() function in C++ STL
  • norm() function in C++ with Examples
  • Removed Features of C++17
  • Conversion Operators in C++
  • Clockwise/Spiral Rule in C/C++ with Examples
  • C++ STL - Vector in Reverse Order
  • Function Overloading in C++
  • Power Function in C/C++
  • < iomanip > Header in C++
  • How to Use the Not-Equal (!=) Operator in C++?
  • Structure of C++ Program
  • Chain of Pointers in C with Examples

The “ Rule of  Five” is a guideline for efficient and bug-free programming in C++. The Rule of Five states that,

If any of the below functions is defined for a class, then it is better to define all of them.

It includes the following functions of a class:

  • Copy Constructor
  • Copy Assignment Operator
  • Move Constructor
  • Move Assignment Operator

The Rule of Big Five is an extension of the Rule of Three to include move semantics. The Rule of Three, consists of a destructor, copy constructor, and, copy assignment operator, use all these three functions when you are dealing with dynamically allocated resources Whereas The Rule of Five includes two more functions i.e. move constructor and move assignment operator .

Need for Rule of Five in C++

In C++ “The Rule of Big Five” is needed to properly manage the resources and efficiently handle objects. Following are the important reasons why we should use the Rule of the Big Five:

  • Assume that you have some dynamically allocated resources in the object and you copy them using shallow copy. This will lead to problems like segmentation faults when the source object is destroyed. Similar thing will happen with copy assignment, move constructor and move assignment operator.
  • By implementing Rule of Big Five properly we can make sure that there are no resource leaks. This can be achieved by ensuring that all the dynamically allocated memory or any other resources are released appropriately.

Let’s discuss each of the five special member functions that a class should define in detail

1. Destructor

The Destructor is used for removing/freeing up all the resources that an object has taken throughout its lifetime.With the help of this destructor, we make sure that any resources taken by objects are properly released before the object is no longer in scope.

2. Copy Constructor

Copy Constructor is used to make a new object by copying an existing object. Copy constructor is invoked when we use it to pass an object by value or when we make a copy explicitly. mainly we use copy constructor to replicate an already existing object.

3. Copy Assignment Operator

Copy Assignment Operator is a special type of function that takes care of assigning the data of one object to another object. It gets called when you use this assignment operator (=) between objects.

4. Move Constructor

Move Constructor is one of the member functions that is used to transfer the ownership of resources from one object to another. This job can easily be done by this move constructor by using a temporary object called rvalue

Explanation: In the above syntax, “noexcept” is used to indicate that the given function, like the move constructor in this case, does not throw any kind of exceptions. The move constructor is specifically designed to handle temporary objects and it requires an rvalue reference (ClassName&& other) as a parameter.

5. Move Assignment Operator

The Move Assignment Operator is comparable to the Move Constructor. It is used when an existing object is assigned the value of an rvalue. It is activated when you use the assignment operator (=) to assign the data of a temporary object(value) to an existing object.

The below example demonstrates the use of all five member functions: Destructor, Copy Constructor, Copy Assignment Operator, Move Constructor, and Move Assignment Operator.

In C++ “The Rule of Big Five” is used to ensure that the memory is properly handled i.e. memory allocation and deallocation is done properly and also resource management. It is an extension of Rule of Three. This rule says that we should use or try to use all the five functions (Destructor, Copy Constructor, Copy Assignment Operator, Move Constructor, and Move Assignment Operator) even if initially we require only one so that we can achieve application optimization, less bugs, efficient code and manage the resources efficiently.

Please Login to comment...

Similar reads.

  • C++-Class and Object
  • C++-Constructors
  • C++-Destructors
  • cpp-constructor
  • Geeks Premier League

Improve your Coding Skills with Practice

 alt=

What kind of Experience do you want to share?

This browser is no longer supported.

Upgrade to Microsoft Edge to take advantage of the latest features, security updates, and technical support.

C++ At Work

Copy Constructors, Assignment Operators, and More

Paul DiLascia

Code download available at: CAtWork0509.exe (276 KB) Browse the Code Online

Q I have a simple C++ problem. I want my copy constructor and assignment operator to do the same thing. Can you tell me the best way to accomplish this?

A At first glance this seems like a simple question with a simple answer: just write a copy constructor that calls operator=.

Or, alternatively, write a common copy method and call it from both your copy constructor and operator=, like so:

This code works fine for many classes, but there's more here than meets the eye. In particular, what happens if your class contains instances of other classes as members? To find out, I wrote the test program in Figure 1 . It has a main class, CMainClass, which contains an instance of another class, CMember. Both classes have a copy constructor and assignment operator, with the copy constructor for CMainClass calling operator= as in the first snippet. The code is sprinkled with printf statements to show which methods are called when. To exercise the constructors, cctest first creates an instance of CMainClass using the default ctor, then creates another instance using the copy constructor:

Figure 1 Copy Constructors and Assignment Operators

If you compile and run cctest, you'll see the following printf messages when cctest constructs obj2:

The member object m_obj got initialized twice! First by the default constructor, and again via assignment. Hey, what's going on?

In C++, assignment and copy construction are different because the copy constructor initializes uninitialized memory, whereas assignment starts with an existing initialized object. If your class contains instances of other classes as data members, the copy constructor must first construct these data members before it calls operator=. The result is that these members get initialized twice, as cctest shows. Got it? It's the same thing that happens with the default constructor when you initialize members using assignment instead of initializers. For example:

As opposed to:

Using assignment, m_obj is initialized twice; with the initializer syntax, only once. So, what's the solution to avoid extra initializations during copy construction? While it goes against your instinct to reuse code, this is one situation where it's best to implement your copy constructor and assignment operator separately, even if they do the same thing. Calling operator= from your copy constructor will certainly work, but it's not the most efficient implementation. My observation about initializers suggests a better way:

Now the main copy ctor calls the member object's copy ctor using an initializer, and m_obj is initialized just once by its copy ctor. In general, copy ctors should invoke the copy ctors of their members. Likewise for assignment. And, I may as well add, the same goes for base classes: your derived copy ctor and assignment operators should invoke the corresponding base class methods. Of course, there are always times when you may want to do something different because you know how your code works—but what I've described are the general rules, which are to be broken only when you have a compelling reason. If you have common tasks to perform after the basic objects have been initialized, you can put them in a common initialization method and call it from your constructors and operator=.

Q Can you tell me how to call a Visual C++® class from C#, and what syntax I need to use for this?

Sunil Peddi

Q I have an application that is written in both C# (the GUI) and in classic C++ (some business logic). Now I need to call from a DLL written in C++ a function (or a method) in a DLL written in Visual C++ .NET. This one calls another DLL written in C#. The Visual C++ .NET DLL acts like a proxy. Is this possible? I was able to use LoadLibrary to call a function present in the Visual C++ .NET DLL, and I can receive a return value, but when I try to pass some parameters to the function in the Visual C++ .NET DLL, I get the following error:

How can I resolve this problem?

Giuseppe Dattilo

A I get a lot of questions about interoperability between the Microsoft® .NET Framework and native C++, so I don't mind revisiting this well-covered topic yet again. There are two directions you can go: calling the Framework from C++ or calling C++ from the Framework. I won't go into COM interop here as that's a separate issue best saved for another day.

Let's start with the easiest one first: calling the Framework from C++. The simplest and easiest way to call the Framework from your C++ program is to use the Managed Extensions. These Microsoft-specific C++ language extensions are designed to make calling the Framework as easy as including a couple of files and then using the classes as if they were written in C++. Here's a very simple C++ program that calls the Framework's Console class:

To use the Managed Extensions, all you need to do is import <mscorlib.dll> and whatever .NET assemblies contain the classes you plan to use. Don't forget to compile with /clr:

Your C++ code can use managed classes more or less as if they were ordinary C++ classes. For example, you can create Framework objects with operator new, and access them using C++ pointer syntax, as shown in the following:

Here, the String s is declared as pointer-to-String because String::Format returns a new String object.

The "Hello, world" and date/time programs seem childishly simple—and they are—but just remember that however complex your program is, however many .NET assemblies and classes you use, the basic idea is the same: use <mscorlib.dll> and whatever other assemblies you need, then create managed objects with new, and use pointer syntax to access them.

So much for calling the Framework from C++. What about going the other way, calling C++ from the Framework? Here the road forks into two options, depending on whether you want to call extern C functions or C++ class member functions. Again, I'll take the simpler case first: calling C functions from .NET. The easiest thing to do here is use P/Invoke. With P/Invoke, you declare the external functions as static methods of a class, using the DllImport attribute to specify that the function lives in an external DLL. In C# it looks like this:

This tells the compiler that MessageBox is a function in user32.dll that takes an IntPtr (HWND), two Strings, and an int. You can then call it from your C# program like so:

Of course, you don't need P/Invoke for MessageBox since the .NET Framework already has a MessageBox class, but there are plenty of API functions that aren't supported directly by the Framework, and then you need P/Invoke. And, of course, you can use P/Invoke to call C functions in your own DLLs. I've used C# in the example, but P/Invoke works with any .NET-based language like Visual Basic® .NET or JScript®.NET. The names are the same, only the syntax is different.

Note that I used IntPtr to declare the HWND. I could have got away with int, but you should always use IntPtr for any kind of handle such as HWND, HANDLE, or HDC. IntPtr will default to 32 or 64 bits depending on the platform, so you never have to worry about the size of the handle.

DllImport has various modifiers you can use to specify details about the imported function. In this example, CharSet=CharSet.Auto tells the Framework to pass Strings as Unicode or Ansi, depending on the target operating system. Another little-known modifier you can use is CallingConvention. Recall that in C, there are different calling conventions, which are the rules that specify how the compiler should pass arguments and return values from one function to another across the stack. The default CallingConvention for DllImport is CallingConvention.Winapi. This is actually a pseudo-convention that uses the default convention for the target platform; for example, StdCall (in which the callee cleans the stack) on Windows® platforms and CDecl (in which the caller cleans the stack) on Windows CE .NET. CDecl is also used with varargs functions like printf.

The calling convention is where Giuseppe ran into trouble. C++ uses yet a third calling convention: thiscall. With this convention, the compiler uses the hardware register ECX to pass the "this" pointer to class member functions that don't have variable arguments. Without knowing the exact details of Giuseppe's program, it sounds from the error message that he's trying to call a C++ member function that expects thiscall from a C# program that's using StdCall—oops!

Aside from calling conventions, another interoperability issue when calling C++ methods from the Framework is linkage: C and C++ use different forms of linkage because C++ requires name-mangling to support function overloading. That's why you have to use extern "C" when you declare C functions in C++ programs: so the compiler won't mangle the name. In Windows, the entire windows.h file (now winuser.h) is enclosed in extern "C" brackets.

While there may be a way to call C++ member functions in a DLL directly using P/Invoke and DllImport with the exact mangled names and CallingConvention=ThisCall, it's not something to attempt if you're in your right mind. The proper way to call C++ classes from managed code—option number two—is to wrap your C++ classes in managed wrappers. Wrapping can be tedious if you have lots of classes, but it's really the only way to go. Say you have a C++ class CWidget and you want to wrap it so .NET clients can use it. The basic formula looks something like this:

The pattern is the same for any class. You write a managed (__gc) class that holds a pointer to the native class, you write a constructor and destructor that allocate and destroy the instance, and you write wrapper methods that call the corresponding native C++ member functions. You don't have to wrap all the member functions, only the ones you want to expose to the managed world.

Figure 2 shows a simple but concrete example in full detail. CPerson is a class that holds the name of a person, with member functions GetName and SetName to change the name. Figure 3 shows the managed wrapper for CPerson. In the example, I converted Get/SetName to a property, so .NET-based programmers can use the property syntax. In C#, using it looks like this:

Figure 3 Managed Person Class

Figure 2 Native CPerson Class

Using properties is purely a matter of style; I could equally well have exposed two methods, GetName and SetName, as in the native class. But properties feel more like .NET. The wrapper class is an assembly like any other, but one that links with the native DLL. This is one of the cool benefits of the Managed Extensions: You can link directly with native C/C++ code. If you download and compile the source for my CPerson example, you'll see that the makefile generates two separate DLLs: person.dll implements a normal native DLL and mperson.dll is the managed assembly that wraps it. There are also two test programs: testcpp.exe, a native C++ program that calls the native person.dll and testcs.exe, which is written in C# and calls the managed wrapper mperson.dll (which in turn calls the native person.dll).

Figure 4** Interop Highway **

I've used a very simple example to highlight the fact that there are fundamentally only a few main highways across the border between the managed and native worlds (see Figure 4 ). If your C++ classes are at all complex, the biggest interop problem you'll encounter is converting parameters between native and managed types, a process called marshaling. The Managed Extensions do an admirable job of making this as painless as possible (for example, automatically converting primitive types and Strings), but there are times where you have to know something about what you're doing.

For example, you can't pass the address of a managed object or subobject to a native function without pinning it first. That's because managed objects live in the managed heap, which the garbage collector is free to rearrange. If the garbage collector moves an object, it can update all the managed references to that object—but it knows nothing of raw native pointers that live outside the managed world. That's what __pin is for; it tells the garbage collector: don't move this object. For strings, the Framework has a special function PtrToStringChars that returns a pinned pointer to the native characters. (Incidentally, for those curious-minded souls, PtrToStringChars is the only function as of this date defined in <vcclr.h>. Figure 5 shows the code.) I used PtrToStringChars in MPerson to set the Name (see Figure 3 ).

Figure 5 PtrToStringChars

Pinning isn't the only interop problem you'll encounter. Other problems arise if you have to deal with arrays, references, structs, and callbacks, or access a subobject within an object. This is where some of the more advanced techniques come in, such as StructLayout, boxing, __value types, and so on. You also need special code to handle exceptions (native or managed) and callbacks/delegates. But don't let these interop details obscure the big picture. First decide which way you're calling (from managed to native or the other way around), and if you're calling from managed to native, whether to use P/Invoke or a wrapper.

In Visual Studio® 2005 (which some of you may already have as beta bits), the Managed Extensions have been renamed and upgraded to something called C++/CLI. Think of the C++/CLI as Managed Extensions Version 2, or What the Managed Extensions Should Have Been. The changes are mostly a matter of syntax, though there are some important semantic changes, too. In general C++/CLI is designed to highlight rather than blur the distinction between managed and native objects. Using pointer syntax for managed objects was a clever and elegant idea, but in the end perhaps a little too clever because it obscures important differences between managed and native objects. C++/CLI introduces the key notion of handles for managed objects, so instead of using C pointer syntax for managed objects, the CLI uses ^ (hat):

As you no doubt noticed, there's also a gcnew operator to clarify when you're allocating objects on the managed heap as opposed to the native one. This has the added benefit that gcnew doesn't collide with C++ new, which can be overloaded or even redefined as a macro. C++/CLI has many other cool features designed to make interoperability as straightforward and intuitive as possible.

Send your questions and comments for Paul to   [email protected] .

Paul DiLascia is a freelance software consultant and Web/UI designer-at-large. He is the author of Windows ++: Writing Reusable Windows Code in C ++ (Addison-Wesley, 1992). In his spare time, Paul develops PixieLib, an MFC class library available from his Web site, www.dilascia.com .

Additional resources

cppreference.com

Search

Copy constructors

A copy constructor of class T is a non-template constructor whose first parameter is T & , const T & , volatile T & , or const volatile T & , and either there are no other parameters, or the rest of the parameters all have default values.

[ edit ] Syntax

[ edit ] explanation.

  • Typical declaration of a copy constructor
  • Forcing a copy constructor to be generated by the compiler
  • Avoiding implicit generation of the copy constructor

The copy constructor is called whenever an object is initialized from another object of the same type (unless overload resolution selects the move constructor as a better match), which includes

  • direct initialization T a ( b ) ; , where b is of type T
  • copy initialization , including by-value function parameter passing, by-value returns ,exception throwing and handling, and T a = b ; , where b is of type T or derived from T

[ edit ] Implicitly-declared copy constructor

If no user-defined copy constructors are provided for a class type ( struct , class , or union ), the compiler will always declare a copy constructor as a non- explicit inline public member of its class. This implicitly-declared copy constructor has the form T::T(const T&) if all of the following is true:

  • all direct and virtual bases of T have copy constructors with references to const or to const volatile as their first parameters
  • all non-static members of T have copy constructors with references to const or to const volatile as their first parameters

Otherwise, the implicitly-declared copy constructor is T :: T ( T & ) . (Note that due to these rules, the implicitly-declared copy constructor cannot bind to a volatile lvalue argument)

[ edit ] Deleted implicitly-declared copy constructor

  • T has non-static data members that cannot be copied (have deleted, inaccessible, or ambiguous copy constructors)
  • T has direct or virtual base class that cannot be copied (has deleted, inaccessible, or ambiguous copy constructors)
  • T has direct or virtual base class with a deleted or inaccessible destructor

[ edit ] Trivial copy constructor

The copy constructor for class T is trivial if all of the following is true:

  • It is not user-provided (that is, it is implicitly-defined or defaulted), and if it is defaulted, its signature is the same as implicitly-defined
  • T has no virtual member functions
  • T has no virtual base classes
  • The copy constructor selected for every direct base of T is trivial
  • The copy constructor selected for every non-static class type (or array of class type) member of T is trivial

A trivial copy constructor is a constructor that creates a bytewise copy of the object representation of the argument, and performs no other action. Objects with trivial copy constructors can be copied by copying their object representations manually, e.g. with std::memmove . All data types compatible with the C language (POD types) are trivially copyable.

[ edit ] Implicitly-defined copy constructor

If the implicitly-declared copy constructor is neither deleted nor trivial, it is defined (that is, a function body is generated and compiled) by the compiler if odr-used . For union types, the implicitly-defined copy constructor copies the object representation (as by std::memmove ). For non-union class types ( class and struct ), the constructor performs full member-wise copy of the object's bases and non-static members, in their initialization order, using direct initialization.

[ edit ] Notes

In many situations, copy constructors are optimized out even if they would produce observable side-effects, see copy elision

[ edit ] Example

  • Recent changes
  • Offline version
  • What links here
  • Related changes
  • Upload file
  • Special pages
  • Printable version
  • Permanent link
  • Page information
  • In other languages
  • This page was last modified on 29 November 2015, at 11:33.
  • This page has been accessed 122,958 times.
  • Privacy policy
  • About cppreference.com
  • Disclaimers

Powered by MediaWiki

Copy constructors

A copy constructor of class T is a non-template constructor whose first parameter is T & , const T & , volatile T & , or const volatile T & , and either there are no other parameters, or the rest of the parameters all have default values.

Explanation

  • Typical declaration of a copy constructor.
  • Forcing a copy constructor to be generated by the compiler.
  • Avoiding implicit generation of the copy constructor.

The copy constructor is called whenever an object is initialized (by direct-initialization or copy-initialization ) from another object of the same type (unless overload resolution selects a better match or the call is elided ), which includes

  • initialization: T a = b ; or T a ( b ) ; , where b is of type T ;
  • function argument passing: f ( a ) ; , where a is of type T and f is void f ( T t ) ;
  • function return: return a ; inside a function such as T f ( ) , where a is of type T , which has no move constructor.

Implicitly-declared copy constructor

If no user-defined copy constructors are provided for a class type ( struct , class , or union ), the compiler will always declare a copy constructor as a non- explicit inline public member of its class. This implicitly-declared copy constructor has the form T :: T ( const T & ) if all of the following are true:

  • each direct and virtual base B of T has a copy constructor whose parameters are B or const B & or const volatile B & ;
  • each non-static data member M of T of class type or array of class type has a copy constructor whose parameters are M or const M & or const volatile M & .

Otherwise, the implicitly-declared copy constructor is T :: T ( T & ) . (Note that due to these rules, the implicitly-declared copy constructor cannot bind to a volatile lvalue argument.)

The implicitly-declared (or defaulted on its first declaration) copy constructor has an exception specification as described in dynamic exception specification (until C++17) exception specification (since C++17)

Deleted implicitly-declared copy constructor

  • T has non-static data members that cannot be copied (have deleted, inaccessible, or ambiguous copy constructors);
  • T has direct or virtual base class that cannot be copied (has deleted, inaccessible, or ambiguous copy constructors);
  • T has direct or virtual base class with a deleted or inaccessible destructor;

Trivial copy constructor

The copy constructor for class T is trivial if all of the following are true:

  • it is not user-provided (that is, it is implicitly-defined or defaulted) , and if it is defaulted, its signature is the same as implicitly-defined (until C++14) ;
  • T has no virtual member functions;
  • T has no virtual base classes;
  • the copy constructor selected for every direct base of T is trivial;
  • the copy constructor selected for every non-static class type (or array of class type) member of T is trivial;

A trivial copy constructor creates a bytewise copy of the object representation of the argument, and performs no other action. TriviallyCopyable objects can be copied by copying their object representations manually, e.g. with std::memmove . All data types compatible with the C language (POD types) are trivially copyable.

Implicitly-defined copy constructor

If the implicitly-declared copy constructor is neither deleted nor trivial, it is defined (that is, a function body is generated and compiled) by the compiler if odr-used . For union types, the implicitly-defined copy constructor copies the object representation (as by std::memmove ). For non-union class types ( class and struct ), the constructor performs full member-wise copy of the object's bases and non-static members, in their initialization order, using direct initialization.

In many situations, copy constructors are optimized out even if they would produce observable side-effects, see copy elision .

Defect reports

The following behavior-changing defect reports were applied retroactively to previously published C++ standards.

  • Pages with unreviewed CWG DR marker

Learn C++

21.12 — Overloading the assignment operator

The copy assignment operator (operator=) is used to copy values from one object to another already existing object .

Related content

As of C++11, C++ also supports “Move assignment”. We discuss move assignment in lesson 22.3 -- Move constructors and move assignment .

Copy assignment vs Copy constructor

The purpose of the copy constructor and the copy assignment operator are almost equivalent -- both copy one object to another. However, the copy constructor initializes new objects, whereas the assignment operator replaces the contents of existing objects.

The difference between the copy constructor and the copy assignment operator causes a lot of confusion for new programmers, but it’s really not all that difficult. Summarizing:

  • If a new object has to be created before the copying can occur, the copy constructor is used (note: this includes passing or returning objects by value).
  • If a new object does not have to be created before the copying can occur, the assignment operator is used.

Overloading the assignment operator

Overloading the copy assignment operator (operator=) is fairly straightforward, with one specific caveat that we’ll get to. The copy assignment operator must be overloaded as a member function.

This prints:

This should all be pretty straightforward by now. Our overloaded operator= returns *this, so that we can chain multiple assignments together:

Issues due to self-assignment

Here’s where things start to get a little more interesting. C++ allows self-assignment:

This will call f1.operator=(f1), and under the simplistic implementation above, all of the members will be assigned to themselves. In this particular example, the self-assignment causes each member to be assigned to itself, which has no overall impact, other than wasting time. In most cases, a self-assignment doesn’t need to do anything at all!

However, in cases where an assignment operator needs to dynamically assign memory, self-assignment can actually be dangerous:

First, run the program as it is. You’ll see that the program prints “Alex” as it should.

Now run the following program:

You’ll probably get garbage output. What happened?

Consider what happens in the overloaded operator= when the implicit object AND the passed in parameter (str) are both variable alex. In this case, m_data is the same as str.m_data. The first thing that happens is that the function checks to see if the implicit object already has a string. If so, it needs to delete it, so we don’t end up with a memory leak. In this case, m_data is allocated, so the function deletes m_data. But because str is the same as *this, the string that we wanted to copy has been deleted and m_data (and str.m_data) are dangling.

Later on, we allocate new memory to m_data (and str.m_data). So when we subsequently copy the data from str.m_data into m_data, we’re copying garbage, because str.m_data was never initialized.

Detecting and handling self-assignment

Fortunately, we can detect when self-assignment occurs. Here’s an updated implementation of our overloaded operator= for the MyString class:

By checking if the address of our implicit object is the same as the address of the object being passed in as a parameter, we can have our assignment operator just return immediately without doing any other work.

Because this is just a pointer comparison, it should be fast, and does not require operator== to be overloaded.

When not to handle self-assignment

Typically the self-assignment check is skipped for copy constructors. Because the object being copy constructed is newly created, the only case where the newly created object can be equal to the object being copied is when you try to initialize a newly defined object with itself:

In such cases, your compiler should warn you that c is an uninitialized variable.

Second, the self-assignment check may be omitted in classes that can naturally handle self-assignment. Consider this Fraction class assignment operator that has a self-assignment guard:

If the self-assignment guard did not exist, this function would still operate correctly during a self-assignment (because all of the operations done by the function can handle self-assignment properly).

Because self-assignment is a rare event, some prominent C++ gurus recommend omitting the self-assignment guard even in classes that would benefit from it. We do not recommend this, as we believe it’s a better practice to code defensively and then selectively optimize later.

The copy and swap idiom

A better way to handle self-assignment issues is via what’s called the copy and swap idiom. There’s a great writeup of how this idiom works on Stack Overflow .

The implicit copy assignment operator

Unlike other operators, the compiler will provide an implicit public copy assignment operator for your class if you do not provide a user-defined one. This assignment operator does memberwise assignment (which is essentially the same as the memberwise initialization that default copy constructors do).

Just like other constructors and operators, you can prevent assignments from being made by making your copy assignment operator private or using the delete keyword:

Note that if your class has const members, the compiler will instead define the implicit operator= as deleted. This is because const members can’t be assigned, so the compiler will assume your class should not be assignable.

If you want a class with const members to be assignable (for all members that aren’t const), you will need to explicitly overload operator= and manually assign each non-const member.

guest

Destructor, Copy Constructor, and Assignment Operator Overloading

Understand the importance of copy constructors and destructors along with their implementation.

  • Problems with shallow copy implementation

Copy constructor and assignment operator overloading ( operator=() )

Get hands-on with 1200+ tech skills courses.

条款9:利用destructors避免泄露资源

copy constructor assignment operator destructor

对指针说拜拜。承认吧,你从未真正喜欢过它,对不?

好,你不需要对所有指针说拜拜,但是你真的得对那些用来操控局部性资源(local resources)的指针说莎唷娜拉了。

举个例子,你正在为“小动物收养保护中心”(一个专门为小狗小猫寻找收养家庭的组织)编写一个软件。收养中心每天都会产生一个文件,其中有它所安排的当天收养个案。你的工作就是写一个程序,读这些文件,然后为每一个收养个案做适当处理。

合理的想法是定义一个抽象基类(abstract base class)ALA("Adorable Litle Animal"),再从中派生出针对小狗和小猫的具体类(concrete classes)。其中有个虚函数processAdoption,负责“因动物种类而异”的必要处理动作。

copy constructor assignment operator destructor

你需要一个函数,读取文件内容,并视文件内容产生一个Puppyobject或一个Kitten object。这个任务非常适合用virtual constructor完成,那是条款25中描述的一种函数。

对本目的而言,以下声明便是我们所需要的:

你的程序核心大约是一个类似这样的函数:

这个函数走遍dataSource,处理它所获得的每一条信息。

唯一需要特别谨慎的是,它必须在每次迭代的最后,记得将pa删除。这是必要的,因为每当readALA被调用,便产生一个新的 heap object。如果没有调用 delete,这个循环很快便会出现资源泄漏的问题。

现在请考虑: 如果pa->processAdoption抛出一个exception,会发生什么事情。processAdoptions 无法捕捉它,所以这个 exception 会传播到 processAdoptions的调用端。 processAdoptions 函数内“位于pa->processAdoption 之后的所有语句”都会被跳过,不再执行,这也意味pa不会被删除。结果呢,只要pa->processAdoption 抛出一个 exception,processAdoptions 便发生一次资源泄漏。

要避免这一点,很简单:

但你的程序因而被try 语句块和catch 语句块搞得乱七八糟。

更重要的是,你被迫重复撰写其实可被正常路线和异常路线共享的清理代码(cleanup code)本例指的是delete动作。

这对程序的维护造成困扰,撰写时很烦人,感觉也不理想。不论我们是以正常方式或异常方式(抛出一个exception)离开processAdoptions函数,我们都需要删除pa,那么何不集中于一处做这件事情呢?

其实不必大费周章, 只要我们能够将“一定得执行的清理代码”移到processAdoptions函数的某个局部对象的destructor 内即可。 因为局部对象总是会在函数结束时被析构,不论函数如何结束(唯一例外是你调用longjmp而结束 。longjmp 的这个缺点正是C++ 支持exceptions的最初的主要原因)。 于是,我们真正感兴趣的是,如何把delete 动作从 processAdoptions 函数移到函数内某个局部对象的destructor内。

解决办法就是,以一个“类似指针的对象”取代指针pa,如此一来,当这个类似指针的对象被(自动)销毁,我们可以令其destructor 调用delete。

“行为类似指针(但动作更多)”的对象我们称为smart pointers。 如条款28所言,你可以做出非常灵巧的“指针类似物”。本例倒是不需要什么特别高档的产品,我们只要求它在被销毁(由于即将离开其scope)之前删除它所指的对象,就可以啦。

技术上这并不困难,我们甚至不需要自己动手。C++标准程序库(见条款E49)提供了一个名为auto_ptr的class template,其行为正是我们所需要的。每个auto_ptr的constructor 都要求获得一个指向 heap object 的指针;其destructoy会将该heapobject 删除。

如果只显示这些基本功能,auto_ptr 看起来像这样:

auto_ptr 标准版远比上述复杂得多。上述这个剥掉一层皮的东西并不适合实际运用2(至少还需加上copy constructor,assignment operator 及条款28所讨论的指针仿真函数operator*和operator->),但是其背后的观念应该很清楚了: 以auto_ptr 对象取代原始指针,就不需再担心heap objects没有被删除一一即使是在exceptions被抛出的情况下。

注意,由于auto ptr destructor 采用“单一对象”形式的delete,所以auto ptr 不适合取代(或说包装)数组对象的指针。如果你希望有一个类似 autoptr的template可用于数组身上,你得自己动手写一个。不过如果真是这样,或许更好的选择是以vector 取代数组。 以auto_ptr对象取代原始指针之后,processAdoptions 看起来像这样:

这一版和原先版本的差异只有两处。

  • 第一,pa被声明为一个 auto_ptr<ALA>对象,不再是原始的 ALA*指针;
  • 第二,循环最后不再有delete 语句。就这样啦,其他每样东西都没变,除了析构动作外,auto_ptr 对象的行为和正常指针完全一样。很简单,不是吗?

隐藏在auto ptr背后的观念一—以一个对象存放“必须自动释放的资源”,并依赖该对象的destructor 释放一—亦可对“以指针为本”以外的资源施行。

考虑图形界面(GUT)应用软件中的某个函数,它必须产生一个窗口以显示某些信息:

许多窗口系统都有 C语言接口,运行诸如 createWindow 和 destroyWindow这类函数,取得或释放窗口(被视为一种资源)。如果在信息显示于的过程中发生exception,w所持有的那个窗口将会遗失,其他动态分配的任何资源也会遗失。

解决之道和先前一样,设计一个class,令其constructor 和destructor 分别取得资源和释放资源:

这看起来就像auto_ptr template 一样,只不过其赋值动作(assignment)和复制动作(copying)被明确禁止了(见条款E27)。

此外,它有一个隐式类型转换操作符,可用来将一个 windowHandle 转换为一个 WINDOW HANDLE。

这项能力对于WindowHandleobject 的实用性甚有必要,意味你可以像在任何地方正常使用原始的WINDOW_HANDLE一样使用一个 windowHandle(不过条款5也告诉你为什么应该特别小心隐式类型转换操作符)。  

有了这个 WindowHandle class,我们可以重写 displayInfo如下:

现在即使 displayInfo函数内抛出 exception,createWindow 所产生的窗口还是会被销毁。

只要坚持这个规则,把资源封装在对象内,通常便可以在exceptions 出现时避免泄漏资源。

但如果exception 是在你正取得资源的过程中抛出的,例如在一个“正在抓取资源”的class constructor 内,会发生什么事呢?

如果exception 是在此类资源的自动析构过程中抛出的,又会发生什么事呢?此情况下constructors和destructors 是否需要特殊设计?

是的,它们需要,你可以在条款 10和条款 11中学到这些技术。  

copy constructor assignment operator destructor

“相关推荐”对你有帮助么?

copy constructor assignment operator destructor

请填写红包祝福语或标题

copy constructor assignment operator destructor

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。 2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

copy constructor assignment operator destructor

IMAGES

  1. class constructor, destructor, copy constructor and assignment operator

    copy constructor assignment operator destructor

  2. Destructors, Copy Constructors & Copy Assignment Operators

    copy constructor assignment operator destructor

  3. The Destructor and the Assignment Operator

    copy constructor assignment operator destructor

  4. C++ : Does C++ create default "Constructor/Destructor/Copy Constructor

    copy constructor assignment operator destructor

  5. Copy Constructor in C++

    copy constructor assignment operator destructor

  6. C++ : Under what circumstances must I provide, assignment operator

    copy constructor assignment operator destructor

VIDEO

  1. Copy Constructor in C++ in Hindi (Lec-23)

  2. COMSC210 Module7 6

  3. C++ class copy constructor [3]

  4. COMSC210 Module4 3

  5. How to implement the rule of three's copy constructor

  6. Constructor & Destructor in Multiple Inheritance || OOP Inheritance

COMMENTS

  1. The copy constructor and assignment operator

    The copy constructor is for creating a new object. It copies an existing object to a newly constructed object.The copy constructor is used to initialize a new instance from an old instance. It is not necessarily called when passing variables by value into functions or as return values out of functions. The assignment operator is to deal with an ...

  2. Copy Constructor vs Assignment Operator in C++

    But, there are some basic differences between them: Copy constructor. Assignment operator. It is called when a new object is created from an existing object, as a copy of the existing object. This operator is called when an already initialized object is assigned a new value from another existing object. It creates a separate memory block for ...

  3. Copy constructors and copy assignment operators (C++)

    Use an assignment operator operator= that returns a reference to the class type and takes one parameter that's passed by const reference—for example ClassName& operator=(const ClassName& x);. Use the copy constructor. If you don't declare a copy constructor, the compiler generates a member-wise copy constructor for you.

  4. What's the difference between assignment operator and copy constructor?

    Copy constructor is called when a new object is created from an existing object, as a copy of the existing object. And assignment operator is called when an already initialized object is assigned a new value from another existing object. Example-. t2 = t1; // calls assignment operator, same as "t2.operator=(t1);"

  5. Copy constructors

    If this satisfies the requirements of a constexpr constructor (until C++23) constexpr function (since C++23), the generated copy constructor is constexpr. The generation of the implicitly-defined copy constructor is deprecated if T has a user-defined destructor or user-defined copy assignment operator. (since C++11)

  6. Copy Constructor in C++

    A copy constructor is called when a new object is created from an existing object, as a copy of the existing object. The assignment operator is called when an already initialized object is assigned a new value from another existing object. In the above example (1) calls the copy constructor and (2) calls the assignment operator.

  7. Copy assignment operator

    A copy assignment operator is a non-template non-static member function with the name operator = that can be called with an argument of the same class type and copies the content of the ... The generation of the implicitly-defined copy assignment operator is deprecated if T has a user-declared destructor or user-declared copy constructor ...

  8. 14.14

    The rule of three is a well known C++ principle that states that if a class requires a user-defined copy constructor, destructor, or copy assignment operator, then it probably requires all three. In C++11, this was expanded to the rule of five, which adds the move constructor and move assignment operator to the list.

  9. Copy constructors, assignment operators,

    The first line runs the copy constructor of T, which can throw; the remaining lines are assignment operators which can also throw. HOWEVER, if you have a type T for which the default std::swap() may result in either T's copy constructor or assignment operator throwing, you are

  10. The rule of three/five/zero

    Rule of three. If a class requires a user-defined destructor, a user-defined copy constructor, or a user-defined copy assignment operator, it almost certainly requires all three. Because C++ copies and copy-assigns objects of user-defined types in various situations (passing/returning by value, manipulating a container, etc), these special ...

  11. Destructors (C++)

    Explicitly defining a destructor, copy constructor, or copy assignment operator prevents implicit definition of the move constructor and the move assignment operator. In this case, failing to provide move operations is usually, if copying is expensive, a missed optimization opportunity. See also. Copy Constructors and Copy Assignment Operators

  12. The Rule of Five in C++

    It includes the following functions of a class: Destructor; Copy Constructor; Copy Assignment Operator; Move Constructor; Move Assignment Operator; The Rule of Big Five is an extension of the Rule of Three to include move semantics. The Rule of Three, consists of a destructor, copy constructor, and, copy assignment operator, use all these three functions when you are dealing with dynamically ...

  13. C++ at Work: Copy Constructors, Assignment Operators, and More

    Figure 1 Copy Constructors and Assignment Operators // cctest.cpp: Simple program to illustrate a problem calling // operator= from copy constructor. ... You write a managed (__gc) class that holds a pointer to the native class, you write a constructor and destructor that allocate and destroy the instance, and you write wrapper methods that ...

  14. PDF Copy Constructors and Assignment Operators

    Writing Copy Constructors For the rest of this handout, we'll discuss copy constructors and assignment operators through a case study of the DebugVector class.DebugVector is a modified version of the CS106 Vector whose constructor and destructor write creation and destruction information to cout.That way, if you're writing

  15. Copy constructors

    The copy constructor is called whenever an object is initialized from another object of the same type (unless overload resolution selects the move constructor as a better match), which includes. direct initialization T a(b);, where b is of type T. copy initialization, including by-value function parameter passing, by-value returns ,exception ...

  16. Copy constructors

    The copy constructor is called whenever an object is initialized (by direct-initialization or copy-initialization) from another object of the same type (unless overload resolution selects a better match or the call is elided ), which includes. initialization: T a = b; or T a(b);, where b is of type T ; function argument passing: f(a);, where a ...

  17. 21.12

    21.12 — Overloading the assignment operator. The copy assignment operator (operator=) is used to copy values from one object to another already existing object. As of C++11, C++ also supports "Move assignment". We discuss move assignment in lesson 22.3 -- Move constructors and move assignment .

  18. Destructor, Copy Constructor, and Assignment Operator Overloading

    Matrix Calculator (Overview and Demo) Overloading the Loading/Printing Operators (<< and >>) The Copy Constructor, operator=(), and Destructor Matrix Arithmetic Matrix Unary Arithmetic and Transpose Accumulation, Assignments and Index Operators Matrix Comparison and Relational Operations Matrix Rotation Menu-Based Implementation of the Matrix ...

  19. Under what circumstances must I provide, assignment operator, copy

    The C++ STL classes (like vector, string) have their own copy ctor, overloaded assignment operator and destructor. But in case if your class allocates memory dynamically in the constructor then a naive shallow copy will lead to trouble. In that case you'll have to implement copy ctor, overloaded assignment operator and destructor.

  20. PDF Interfaces

    Abstract classes •Remember, inheritance enables you to define a general class (i.e., a superclass) and later extend it to more specialized classes (i.e., subclasses) •Sometimes, a superclass is so general it cannot be used

  21. 条款9:利用destructors避免泄露资源-CSDN博客

    上述这个剥掉一层皮的东西并不适合实际运用2(至少还需加上copy constructor,assignment operator 及条款28所讨论的指针仿真函数operator*和operator->),但是其背后的观念应该很清楚了: 以auto_ptr 对象取代原始指针,就不需再担心heap objects没有被删除一一即使是在exceptions ...

  22. Why must I declare copy & move constructors when declaring destructors?

    Class Application defines a non-default destructor but does not define a copy constructor, a copy assignment operator, a move constructor or a move assignment operator [hicpp-special-member-functions]. There're also [cppcoreguidelines-special-member-functions] reminders with the same message. The current workaround is to explicitly write all of ...

  23. destructor and copy-constructor calling..(why does it get called at

    Then you return another object (again, rather than a reference) so another copy must be made (a second call to the copy constructor). and just after that Destruct(1) gets called twice before ( d ) is printed. Those objects that you just created with the copy constructors? They just went out of scope and their destructors were called.

  24. c++

    This is why you are seeing more destructor calls than constructor calls. You need to add logging to the copy and move constructors of the Testing class. You should also log each object's this pointer instead of (or at least in addition to) its object_id. That will give you a better idea of what is actually going on with the objects: