Конструктор может выбрасывать исключения в следующих случаях:
class ResourceHolder {
int* resource;
public:
ResourceHolder(size_t size) {
resource = new int[size]; // Может бросить std::bad_alloc
if (size > 1000) {
throw std::runtime_error("Size too large"); // Явное исключение
}
}
};
class DatabaseConnection {
ConnectionHandle handle;
public:
DatabaseConnection() {
handle = connect_to_database(); // Может бросить DatabaseException
if (!handle.is_valid()) {
throw ConnectionFailed("Cannot establish connection");
}
}
};
Если конструктор бросает исключение:
class SafeObject {
std::vector<int> data;
FileHandler file;
public:
SafeObject(const std::string& filename)
: data(1'000'000), // Может бросить std::bad_alloc
file(filename) { // Может бросить FileException
// Если исключение брошено здесь - деструкторы data и file будут вызваны
}
};
class LeakyResource {
int* ptr1;
int* ptr2;
public:
LeakyResource() {
ptr1 = new int[100]; // Если здесь бросить исключение - утечка
ptr2 = new int[200]; // Если здесь бросить исключение - утечка ptr1
}
};
Решение: Использовать умные указатели или RAII-обертки
class SafeResource {
std::unique_ptr<int[]> ptr1;
std::unique_ptr<int[]> ptr2;
public:
SafeResource() : ptr1(new int[100]), ptr2(new int[200]) {
// При исключении ресурсы будут автоматически освобождены
}
};
Лучшая практика - инициализировать ресурсы в списке инициализации:
class RAIIExample {
std::unique_ptr<Resource> res1;
std::unique_ptr<Resource> res2;
public:
RAIIExample()
: res1(acquire_resource()), // Если бросит исключение - res1 не создастся
res2(acquire_resource()) { // Если бросит здесь - res1 будет уничтожен
// Тело конструктора
}
};
Исключения в конструкторах допустимы и часто необходимы при:
Главные правила:
Правильная обработка исключений в конструкторах - ключ к созданию надежных и безопасных C++ классов.