leesangwon0114

I am Research Engineer. Currently working in KT.

C++Intermediate 10. C++기본문법_conversion#2

30 Oct 2018 » c++

codenuri 강석민 강사 강의 내용기반으로 정리한 내용입니다.


return type resolver

#include <iostream>
#include <cstdlib>
using namespace std;

int* memAlloc(int sz)
{
    return (int*)malloc(sz);
}

int main()
{
    double* p = memAlloc(40);
}

return 포인터를 double로 받고 싶을 때

템플릿 인자를 함수인자로 안쓰고 return 타입을 사용해 컴파일러가 추론할 수 없어 double로 전달해야함

#include <iostream>
#include <cstdlib>
using namespace std;

template<typename T> T* memAlloc(int sz)
{
    return (int*)malloc(sz);
}

int main()
{
    // double* p = memAlloc(40);
    double* p = memAlloc<double>(40);
}

double을 적지 않고도 사용할 수 있도록

double* p1 = memAlloc(40);

int* p2 = memAlloc(40);


#include <iostream>
#include <cstdlib>
using namespace std;

/*
template<typename T> T* memAlloc(int sz)
{
    return (int*)malloc(sz);
}
*/
class memAlloc
{
    int size;
public:
    inline memAlloc(int sz) : size(sz) {}

    template<typename T> operator T*()
    {
        return (T*)malloc(size);
    }
};

int main()
{
    double* p1 = memAlloc(40); // 클래스 이름() : 임시객체..
    // 임시객체.operator double*() 을 찾을 것임
    int* p2 = memAlloc(40);
}

safe bool

#include <iostream>
using namespace std;

int main()
{
    int n = 0;
    cin >> n; // 'a'

    if (cin.fail())
        cout << "실패" << endl;

    if (cin)
        cout << "성공" << endl;
}

if 문의 객체가 if문에 들어갈 수 있는 요소로 변환이 된다는 뜻

if(bool, 정수, 포인터, 실수) 만 올 수 있음

cin.operator void*() 로 변환이 되는 것임 -> C++98/03

cin.operator bool() -> C++11

옛날에는 void하고 왜 11로 와서 bool로 바뀌었는가?

class istream
{
public:
    bool fail() { return false;}

    // 방법 1. bool로 변환
    operator bool() {return fail() ? false : true;}
}

istream cin;

int main()
{
    int n = 0;

    if (cin) {}

    cin << n; // 사용자가 잘못적을 수 있음 -> 컴파일시 에러나와야하는데 컴파일은 잘됨

    // cin은 bool로 변환이되고 결국 정수라 쉬프트 연산이 가능해짐
}

bool로 변환 단점 : shift 연산이 허용된다.

bool로 변환하면 문제점이 크니까 void*로 변환하자

class istream
{
public:
    bool fail() { return false;}

    // 방법 2. void*로 변환
    operator void*() {return fail() ? 0 : this;}
}

istream cin;

int main()
{
    int n = 0;

    if (cin) {}

    cin << n;

    delete cin;
}

void*는 shift 연산 못하니까 error 발생

따라서 C++ 98/03은 if 문에 cin만 넣기위해 void*로 변환함

그러나 delete cin; 이 에러가 안남 -> this로 형변환 되기 때문에…

-> 부스트팀이 함수 포인터로 변환

void true_function() {}

class istream
{
public:
    bool fail() { return false;}

    // 방법 3. 함수 포인터로의 변환
    typedef void(*F)();
    operator F() {return fail() ? 0 : &true_function;}
}

istream cin;

int main()
{
    int n = 0;

    if (cin) {}

    cin << n;

    delete cin;
}

cin « n; delete cin; 모두에 error 발생해서 안전하게 사용가능함

그라나 void(*f)() = cin;

cin이 함수포인터로 변환될 수 있다.

계속 사이드 이팩트 발생

결국 다시 멤버 함수 포인터로의 변환

class istream
{
public:
    bool fail() { return false;}
    
    struct Dummy
    {
        void true_function() {}
    }

    // 방법 4. 멤버 함수 포인터로의 변환
    typedef void(Dummy::*F)();
    operator F() {return fail() ? 0 : &Dummy::true_function;}
}

istream cin;

int main()
{
    int n = 0;

    if (cin) {}

    cin << n;

    delete cin;

    void(*f)() = cin;
}

다시 void(Dummy::*f)() = cin; 이여야하는데 istream 안에 있으므로 error

void(istream::Dummy::*f)() = cin; 이라고 일반 개발자가 적기 어려움

따라서 if 문에 넣을 수 있는 side effect 가 가장 적다.

-> Safe BOOL

if 문에는 넣을 수 있는데 잘못된 기법을 막는 방법으로 결국에는 멤버함수를 이용하는 것을 safe bool이라함

C++ 11에서 해결책 제시

Explicit Conversion Operator

  • C++11 부터는 변환 연산자에도 explicit 를 붙일수 있다.

  • 명시적 변환은 허용되지만 암시적 변환은 될 수 없다.

  • if 문을 사용해서 객체를 조사할 수 있다.

class istream
{
public:
    bool fail() { return false; }
    explicit operator bool() {return fail() ? false: true;}
};

istream cin;

int main()
{
    bool b1 = cin; // error
    bool b2 = static_cast<bool>(cin); // ok.

    if (cin) {} // ok.

    if (cin == false) {} // error
}

brace-init & conversion

class Point
{
    int x, y;
public:
    explicit Point(int a, int b) : x(a), y(b) {}
};

void foo(Point p) {}

int main()
{
    foo({1,1}); // error

    Point p1(1,1);

    Point p2{1,1}; // direct initialize

    Point p3 = {1,1}; // copy initialize -> error
}

brace-init 때매 인자가 2개여도 변환이될수 있으므로 explicit를 붙이면 p3는 error 발생하도록 할 수 있음