Fork me on GitHub

C++ 拷贝构造

12 拷贝构造

  • Create a new object from an existing one
    • For example, when calling a function
// Currency as pass-by-value argument
void func(Currency p)
{
    cout << "X = " << p.dollars();
}

Currency bucks(100, 0);
func(bucks);    // bucks is copied into p
  • 示例二:
#include <iostream>
#include <string>
using namespace std;

static int objectCount = 0;

class HowMany {
public:
    HowMany() { objectCount++; print("HowMany()"); }
    void print(const string& msg = "") {
        if (msg.size() != 0) {
            cout << msg << ": ";
        }
        cout << "objectCount = "
             << objectCount << endl;
    }
    ~HowMany() {
        objectCount--;
        print("~HowMany()");
    }
};

HowMany f(HowMany x) {
    cout << "begin of f " << endl;
    x.print("x argument inside f() ");
    cout << "end of f" << endl;
    return x;
}

int main() {
    HowMany h;
    h.print("after construction of h");
    HowMany h2 = f(h);
    h.print("after call to f()");
}
  • 示例三:
#include <iostream>
#include <string>
using namespace std;

static int objectCount = 0;

class HowMany {
public:
    HowMany() { objectCount++; print("HowMany()"); }
    HowMany(int i) { objectCount++; print("HowMany(int)"); }
    // 拷贝构造
    HowMany(const HowMany& o) { objectCount++; print("HowMany(HM)"); }
    void print(const string& msg = "") {
        if (msg.size() != 0) {
            cout << msg << ": ";
        }
        cout << "objectCount = "
             << objectCount << endl;
    }
    ~HowMany() {
        objectCount--;
        print("~HowMany()");
    }
};

HowMany f(HowMany x) {
    cout << "begin of f " << endl;
    x.print("x argument inside f() ");
    cout << "end of f" << endl;
    return x;
}

int main() {
    HowMany h;
    h.print("after construction of h");
    // 这种方式,是可以初始化 h2 的
    HowMany h2 = 10;
    // HowMany h2 = h;
    HowMany h3 = f(h);
    h.print("after call to f()");
}

12.1 The copy cosntructor

  • Copying is implemented by the copy cosntructor
  • Has the unique signature: T::T(cosnt T&);
    • Call-by-reference is used for the explicit argument
  • C++ builds a copy constructor for you if you don't provide one!
    • Copies each member variable
      • Good for numbers, objects, arrays
    • Copies each pointer
      • Data may become shared!

12.2 class contains pointers

  • 示例一:
#include <iostream>
#include <stdio.h>
#include <cstring>
using namespace std;

class Person {
public:
    Person(const char *s);
    ~Person();
    void print();

// private:
    char *name;
};

Person::Person(const char *s) {
    name = new char[::strlen(s) + 1];
    ::strcpy(name, s);
}

Person::~Person() {
    delete []name;
}

int main() 
{
    Person p1("John");
    Person p2(p1);

    printf("p1.name = %p\n", p1.name);
    printf("p2.name = %p\n", p2.name);
    return 0;
}

// p1.name 和 p2.name 指向同一个地址,析构的时候,会析构两次;
// 程序运行会报错。
  • 示例二:Person copy constructor
#include <iostream>
#include <stdio.h>
#include <cstring>
using namespace std;

class Person {
public:
    Person(const char *s);
    // 自定义拷贝构造
    Person(const Person& w);
    ~Person();
    void print();

// private:
    char *name;
};

Person::Person(const char *s) {
    name = new char[::strlen(s) + 1];
    ::strcpy(name, s);
}

Person::Person(const Person& w) {
    name = new char[::strlen(w.name) + 1];
    ::strcpy(name, w.name);
}

Person::~Person() {
    delete []name;
}

int main() 
{
    Person p1("John");
    Person p2(p1);

    printf("p1.name = %p\n", p1.name);
    printf("p2.name = %p\n", p2.name);
    return 0;
}
  • 总结:

12.3 When are copy constructor called?

  • During call by value
void roster(Person);    // 函数声明

Person child("Tom");    // 创建对象
roster(child);          // 调用函数,参数为对象本身
  • During initialization
Person baby_a("Fred");

// 以下需要使用 copy constructor
Person baby_b = baby_a;  // not an assignment
Person baby_c(baby_a);   // not an assignment
  • During function return
Person f()
{
    Person player("Musk");
    return player;
}

int main()
{
    Person p = f();
    return 0;
}

12.3.1 编译器对拷贝的优化

  • Compilers can "optimize out" copies when safe!
// 示例一:
Person copy_func(char *who) {
    Person local(who);
    local.print();
    return local;   // copy constructor called!
}

// 示例二:
Person nocopy_func(char *who) {
    return Person(who); // no copy needed!
}

12.4 Construction vs. assignment

  • Every object is constructed once.
  • Every object should be destroyed once
    • Failure to invoke delete()
    • Invoking delete() more than once
  • Once an object is constructed, it can be the target of many assignment operations.

12.5 Copy constructor guidelines

  • In general, be explicit
    • Create your own copy constructor -- don't rely on the default
  • If you don't need one, declare a private copy constructor
    • prevents creation of a default copy constructor
    • generates a compiler error if try to pass-by-value
    • don't need a definition

参考资料:

posted @ 2022-06-16 16:26  小a的软件思考  阅读(25)  评论(0编辑  收藏  举报