首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> C++ >> C++ 入門

C++ 面試題:深拷貝建構函數與異常安全

     編輯:C++ 入門

題目

class Foo {
public:
    Foo(A* a, B* b);
    ~Foo() { delete a; delete b; }
    // 實現拷貝建構函數
    // A 和 B 皆為 CopyConstructible
private:
    A* a;
    B* b;
};

標準答案(C++98 風格)

Foo::Foo(const Foo& other) {
    this->a = new A(*other.a);
    this->b = new B(*other.b);
}

深度解析:為什麼這樣寫?

  1. 深拷貝語意:Foo 擁有 A、B 的所有權(解構函數 delete),拷貝必須建立**新物件**,而非共享指標(淺拷貝會導致雙重釋放)。
  2. 異常安全問題:若 new A(*other.a) 成功,new B(*other.b) 拋出異常 → a 已分配卻未賦值給成員 → **記憶體洩漏**。
  3. 強異常安全保證:採用 **Copy-and-Swap** 或 **RAII 智慧指標**。

現代 C++ 最佳實踐

方案一:std::unique_ptr(推薦,C++11+)


#include 
class Foo {
public:
    Foo(std::unique_ptr a, std::unique_ptr b) 
        : a_(std::move(a)), b_(std::move(b)) {}
    // 編譯器自動生成的拷貝建構函數 = delete(unique_ptr 不可拷貝)
    // 若需拷貝,提供 clone:
    Foo(const Foo& other) 
        : a_(other.a_ ? std::make_unique(*other.a_) : nullptr),
          b_(other.b_ ? std::make_unique(*other.b_) : nullptr) {}
    // 移動建構/賦值預設即可
private:
    std::unique_ptr a_;
    std::unique_ptr b_;
};

方案二:Copy-and-Swap(C++98 相容)


class Foo {
public:
    Foo(A* a, B* b) : a_(a), b_(b) {}
    Foo(const Foo& other) : a_(new A(*other.a_)), b_(new B(*other.b_)) {}
    Foo& operator=(Foo other) { // 傳值參數觸發拷貝建構
        swap(*this, other);
        return *this;
    }
    ~Foo() { delete a_; delete b_; }
    friend void swap(Foo& lhs, Foo& rhs) noexcept {
        std::swap(lhs.a_, rhs.a_);
        std::swap(lhs.b_, rhs.b_);
    }
private:
    A* a_;
    B* b_;
};
  • 賦值運算子傳值參數 → 自動調用拷貝建構函數建立臨時副本 → swap 交換資源 → 臨時副本解構釋放舊資源。
  • 若拷貝建構拋出異常,原物件**完全不變**(強異常安全)。

關鍵點總結

議題錯誤寫法正確寫法
淺拷貝a = other.a; b = other.b;深拷貝 new A(*other.a)
異常洩漏分步 new 直接賦值成員Copy-and-Swap / 智慧指標
自賦值未檢查 this == &otherCopy-and-Swap 天然免疫
Rule of Three/Five只寫拷貝建構,缺賦值/解構三/五個函數齊全或 =default/delete
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved