문제
exception 클래스를 상속받는 BadLengthException 클래스를 구현하여 사용자명을 입력받고 조건에 부합할 때 발생하는 예외를 처리하는 문제입니다.
풀이
class BadLengthException : public exception {
private:
string errstr;
//stringstream ss; //Caution
...
...
} catch(BadLengthException e) //Compile error
stringstream 객체를 BadLengthException 클래스의 변수로 선언하면 catch 문에서
컴파일 오류가 발생합니다.
checkUsername 에서 예외가 발생하면서 BadLengthException 객체를 throw합니다.
그리고 catch 문의 매개변수는 BadLengthException 객체 e 인데, throw된 예외의 복사 생성자에 의해 만들어진 객체를 인수로 전달받습니다.
문제는 복사 방식이 얕은 복사(Shallow Copy)에서 발생합니다.
기존 BadLegthException 과 복사된 e 가 동일한 stringstream 객체를 참조하고 있습니다.
try 문의 블럭 범위를 벗어나면 throw된 객체의 stringstream 객체 복사 생성자가 삭제되고, 암묵적으로 BadLengthException 의 복사 생성자도 삭제됩니다.
따라서 e 를 호출할 수 없게 되므로 코드를 컴파일할 수 없습니다.
stringstream을 사용하는 것이 아닌 to_string을 이용하여 변환하는 것이 안전합니다.
...
BadLengthException(int n) {
stringstream ss;
ss << n;
errstr = ss.str();
}
const char * what() const noexcept {
return errstr.c_str();
/*
stringstream ss;
ss << errnum;
return ss.c_str()
-> This is dangerous!
*/
}
...
what 함수는 exception 클래스를 public 접근자로 상속받아 오버로딩으로 구현했습니다.
stringstream 객체, ss 는 what 함수 블록 내에서 선언되었습니다.
함수의 실행이 종료되면 메모리 상에서 사라지기 때문에 ss 를 이용하여 값을 반환하는 것은 메모리 누수 위험이 존재하는 방법입니다.
따라서, 상속자를 통해 ss 를 선언하여 username의 길이를 문자열로 변환해준 뒤, errstr 문자열 변수에 저장해두어 사용했습니다.
전체 코드
#include <iostream>
#include <string>
#include <sstream>
#include <exception>
using namespace std;
/* Define the exception here */
class BadLengthException : public exception {
private:
string errstr;
public:
BadLengthException(int n) {
stringstream ss;
ss << n;
errstr = ss.str();
//errstr = to_string(n);
}
const char * what() const noexcept {
return errstr.c_str();
}
};
bool checkUsername(string username) {
bool isValid = true;
int n = username.length();
if(n < 5) {
throw BadLengthException(n);
}
for(int i = 0; i < n-1; i++) {
if(username[i] == 'w' && username[i+1] == 'w') {
isValid = false;
}
}
return isValid;
}
int main() {
int T; cin >> T;
while(T--) {
string username;
cin >> username;
try {
bool isValid = checkUsername(username);
if(isValid) {
cout << "Valid" << '\n';
} else {
cout << "Invalid" << '\n';
}
} catch (BadLengthException e) {
cout << "Too short: " << e.what() << '\n';
}
}
return 0;
}
참고
'Coding Test > HackerRank' 카테고리의 다른 글
[C++/STL] Deque-STL (0) | 2022.01.16 |
---|---|
[C++/Class] Abstract Classes - Polymorphism (0) | 2022.01.15 |
[C++/Classes] Virtual Functions (0) | 2022.01.15 |
[C++/Classes] Exceptional Server (0) | 2022.01.15 |
[C++/Classes] Box it! (0) | 2022.01.09 |