| |

VerySource

 Forgot password?
 Register
Search
View: 2238|Reply: 17

Continue to Ask Copy Control

[Copy link]

1

Threads

7

Posts

8.00

Credits

Newbie

Rank: 1

Credits
8.00

 China

Post time: 2020-3-14 18:30:02
| Show all posts |Read mode
A very simple procedure is as follows:

#include <iostream>

using namespace std;

class Foo {
public:
    Foo (int i) {cout << "using int. Done." << endl;}
    ~ Foo () {cout << "deleting. Done." << endl;}
// private:
    Foo (const Foo&f) {cout << "using copying. Done." << endl;}
};

int main () {
  Foo f = 100;
  return 0;
}


The result is:
using int. done.
deleting. done.

To analyze the sentence Foo f = 100, you should first call Foo (int) to construct a temporary object, then call the copy constructor Foo (const Foo&f) to construct f, and then delete the temporary object.

But it is strange: the copy constructor Foo (const Foo&f) does not seem to be called, and the destructor is only called once; and if Foo (const Foo&f) is set to private, it cannot be compiled.

Can anyone explain? Thank you
Reply

Use magic Report

0

Threads

14

Posts

15.00

Credits

Newbie

Rank: 1

Credits
15.00

 China

Post time: 2020-6-11 22:30:01
| Show all posts
Analyzing Foo f = 100, it should call Foo(int) to construct a temporary object, and then delete the temporary object.
Reply

Use magic Report

0

Threads

7

Posts

7.00

Credits

Newbie

Rank: 1

Credits
7.00

 China

Post time: 2020-6-12 10:45:01
| Show all posts
------
If Foo(const Foo&f) is set to private, it cannot be compiled.
---------
are u sure???
Reply

Use magic Report

0

Threads

63

Posts

43.00

Credits

Newbie

Rank: 1

Credits
43.00

 China

Post time: 2020-6-12 11:00:01
| Show all posts
Foo f = 100;
equal
Foo f(100);
Reply

Use magic Report

2

Threads

54

Posts

34.00

Credits

Newbie

Rank: 1

Credits
34.00

 China

Post time: 2020-6-12 11:15:01
| Show all posts
To analyze the sentence Foo f = 100, you should first call Foo(int) to construct a temporary object, then call the copy constructor Foo(const Foo&f) to construct f, and then delete the temporary object.
=============================================
In theory, this is the implementation
Reply

Use magic Report

0

Threads

63

Posts

43.00

Credits

Newbie

Rank: 1

Credits
43.00

 China

Post time: 2020-6-12 12:15:01
| Show all posts
Foo f = 100;
equal
Foo f(100);
Reply

Use magic Report

0

Threads

55

Posts

44.00

Credits

Newbie

Rank: 1

Credits
44.00

 Invalid IP Address

Post time: 2020-6-13 09:00:01
| Show all posts
exceptional C++ item 42
Reply

Use magic Report

0

Threads

7

Posts

7.00

Credits

Newbie

Rank: 1

Credits
7.00

 China

Post time: 2020-6-14 18:00:01
| Show all posts
Reprinted:

The type T mentioned in this article refers to UDT, not built-in type
Thanks to ilovecpp, all "*Note" parts are added by his reminder

There are three forms to construct an object:

1. T a;
This is nothing to say, call the default ctor to construct a
However, it should be noted that either T has no ctor, and the compiler synthesizes the default ctor, namely T::T()
If T has other forms of ctor added manually, but there is no T::T(), this statement reports an error because the compiler no longer
Synthesize default ctor for T
*Note 1, if there is no default ctor, but all parameters of a ctor have default values, then T a; also holds


2. T a(v);
This statement explicitly uses v as a parameter to call some of the most suitable ctor that can be called with a single parameter to construct a
This statement form is called direct-initialization by the C++ standard
Two points are emphasized here. One is explicit, which means that the ctor that is explicitly declared can be called in this way.
The second point is the most suitable, this is determined by the overload rules, not so taken for granted, the sample code is as follows
struct T
{
  T(){}
  T(int){}
  operator int(){return 0;}
private:
  T(T&){}
};
T foo() {return T();}
int main()
{
  T a;

  T b(a); // Compile error, the most suitable T(T&) is not accessible, it is private

  T c(foo());// Compile successfully, the temporary object returned by foo() is rvalue, and cannot be bound to a non-const reference
             // Therefore T(T&) is not the most suitable ctor selected by overload rules
             // But rvalue can call a custom implicit conversion cast to int and then call T(int) to construct c
             // That is, T(int) is selected for overload rules

  return 0;
}
This code shows that even if the type is the same, the copy ctor is not necessarily called
If someone suspects that T(T&) is not a copy ctor and thinks that T(const T&) is, please refer to C++ Standard 12.8


3. T a = v;
The form of this statement is called copy-initialization by the C++ standard. This name is very confusing, leading me to
At one time, it was thought that this type of semantics (later explained what is semantic) must call copy ctor
Refer to the C++ standard 8.5/14, there is such a sentence
If the destination type is a (possibly cv-qualified) class type:
--If the initialization is direct-initialization, or if it is
  copy-initialization where the cv-unqualified version of the
  source type is the same class as, or a derived class of, the
  class of the destination, constructors are considered. The
  applicable constructors are enumerated (13.3.1.3), and the
  best one is chosen through overload resolution (13.3). The
  constructor so selected is called to initialize the object,
  with the initializer expression(s) as its argument(s). If no
  constructor applies, or the overload resolution is ambiguous,
  the initialization is ill-formed.
To put it simply, the above meaning is that if T is UDT, in the "copy-initialization and cv- of v
unqualified type is also T (or T-derived class)", the implementation is the same
Same as direct-initialization!
*Note 2, actually copy-initialization in this case is different from direct-initialization,
* The C++ standard states that only T a(v); is to explicitly call ctor, otherwise it is implicitly called, which requires
* The selected ctor cannot be declared as explicit, otherwise the compilation error
*---C++ Standard 12.3.1
* An explicit constructor constructs objects just like non-explicit
* constructors, but does so only where the direct-initialization
* syntax (8.5) or where casts (5.2.9, 5.4) are explicitly used.
The C++ standard also stipulates that if not
--Otherwise (i.e., for the remaining copy-initialization cases),
  user-defined conversion sequences that can convert from the source
  type to the destination type or (when a conversion function is used)
  to a derived class thereof are enumerated as described in 13.3.1.4,
  and the best one is chosen through overload resolution (13.3). If the
  conversion cannot be done or is ambiguous, the initialization is ill-formed.
  The function selected is called with the initializer expression as its
  argument; if the function is a constructor, the call initializes a
  temporary of the destination type. The result of the call (which is
  the temporary for the constructor case) is then used to direct-initialize,
  according to the rules above, the object that is the destination of
  the copy-initialization. In certain cases, an implementation is permitted
  to eliminate the copying inherent in this direct-initialization by
  constructing the intermediate result directly into the object being
  initialized; see 12.2, 12.8.
To put it simply, the statement T a = v; when the type of v is different from T (and not a derived class of T), semantically
First construct a temporary object T with v (or call a custom conversion to implicitly cast to type T or a derived type of T),
Then explicitly call copy ctor to construct a
The reason why it emphasizes semantics is because the standard says that this call can be optimized away, but the semantics exist
The emphasis on explicit means that the copy ctor can be explicit
In addition, it should be emphasized that although the standard here says that after constructing the temporary object T(v) (or implicitly converting v
For type T, static_cast<T>(v)) and then use direct-initialize to construct a directly, the entire statement is executed
The form is T a(T(v)); (static_cast<T>(v) can also be written as T(v) in C syntax), but it is called with T(v)
ctor can only be a copy ctor of T, because the compiler has already performed a custom implicit conversion T(v), cannot
The second time, so you must call the ctor that directly matches the T(v) parameter, which is the copy ctor
Another addition to the above sentence is that the cast of the derived class to the base class is not a custom implicit conversion, it is automatically sent
Raw, so there is another option is Ta (U(v)); and U is a derived class of T! The final call is still copy ctor
Examples are as follows
struct T
{
  T(){}
  T(int){}
  operator int(){return 0;}
private:
  explicit T(T&){}
};
int main()
{
  T a = T(); // Compiled, it is equivalent to implicit call T a(T());
              // The overloading rule uses T(int), which is T a(static_cast<int>(T()));
              // If T::T(int) is declared as explicit, compilation error

  T b = 0; // compilation error, copy ctor can not access, although this call is optimized, but the semantics still exist

  return 0;
}

Here is another example to supplement the explanation
struct T
{
  T(int){}
  explicit T(const T&){}
};
void foo(T)
{
}
int main()
{
  foo(T(0)); // Compile error, according to *Note 2, it is required to implicitly copy the parameters to foo
             // Equivalent to T t = T(0);

  foo(0); // Compile and pass, construct a temporary object T(0) with 0, and then explicitly copy the parameters to foo
             // Equivalent to T t = 0;

  return 0;
}
Because the function's pass-by-value parameters and return-by-value are both copy-initialization, there will be differences in the results as above
Reply

Use magic Report

1

Threads

7

Posts

8.00

Credits

Newbie

Rank: 1

Credits
8.00

 China

 Author| Post time: 2020-6-16 01:30:01
| Show all posts
tokillingme
--------------------------------
are u sure???
--------------------------------

Yes, i am sure. you may try it yourself.




toorangedj
------------------------------------
Foo f = 100;
equal
Foo f(100);
------------------------------------
If this is the case, why can't it be compiled if Foo (const Foo&f) is set to private?
Reply

Use magic Report

0

Threads

7

Posts

7.00

Credits

Newbie

Rank: 1

Credits
7.00

 China

Post time: 2020-6-16 19:00:01
| Show all posts
toluyamin
This is implementation related, I can use vc6 to compile
You can look at my reprinted answer
Reply

Use magic Report

You have to log in before you can reply Login | Register

Points Rules

Contact us|Archive|Mobile|CopyRight © 2008-2023|verysource.com ( 京ICP备17048824号-1 )

Quick Reply To Top Return to the list