更多 C++ 慣用法/構造跟蹤器
外觀
識別在建構函式的初始化列表中初始化兩個或多個物件時丟擲相同異常型別的那個資料成員
構造跟蹤器
當在建構函式的初始化列表中初始化兩個或多個物件,並且它們都可能丟擲相同的異常(std::exception)時,跟蹤哪個物件失敗成為一個棘手的問題,因為只有一個 try 塊可以包圍初始化列表。這樣的 try 塊有一個特殊的名稱,叫做 "建構函式 try 塊",它實際上是一個 "函式 try 塊"。
構造跟蹤器慣用法使用一種簡單的技術來跟蹤初始化列表中物件的成功構造。當物件的建構函式一個接一個地成功完成時,一個計數器簡單地增加。它巧妙地使用括號運算子在對建構函式的呼叫之間插入計數器增量,這一切對類的使用者來說都是不可見的。
#include <iostream>
#include <stdexcept>
#include <cassert>
struct B {
B (char const *) { throw std::runtime_error("B Error"); }
};
struct C {
C (char const *) { throw std::runtime_error("C Error"); }
};
class A {
B b_;
C c_;
enum TrackerType { NONE, ONE, TWO };
public:
A( TrackerType tracker = NONE)
try // A constructor try block.
: b_((tracker = ONE, "hello")) // Can throw std::exception
, c_((tracker = TWO, "world")) // Can throw std::exception
{
assert(tracker == TWO);
// ... constructor body ...
}
catch (std::exception const & e)
{
if (tracker == ONE) {
std::cout << "B threw: " << e.what() << std::endl;
}
else if (tracker == TWO) {
std::cout << "C threw: " << e.what() << std::endl;
}
throw;
}
};
int main (void)
{
try {
A a;
}
catch (std::exception const & e) {
std::cout << "Caught: " << e.what() << std::endl;
}
return 0;
}
雙圓括號是括號運算子用於將賦值放置到跟蹤器中的方式。此慣用法關鍵依賴於 B 和 C 的建構函式至少接受一個引數。如果類 B 或 C 不接受引數,那麼需要編寫一個介面卡類,使介面卡類接受一個虛擬引數並呼叫 B 和 C 的預設建構函式。可以使用 更多 C++ 慣用法/引數化基類 慣用法使用自下而上的混合技術編寫這樣的介面卡。介面卡類也可以完全封裝在類 A 內部。在 conconstructor 類 A 中,跟蹤器引數具有預設值,因此它不會打擾使用者。