08.02

신승빈·2022년 8월 2일
0

KGCA 수업

목록 보기
17/128

Container

Iterator

iterator : 정방향 iterator
reverse_iterator : 역방향 iterator
const_iterator : const형 정방향 iterator
const_reverse_iterator : const형 역방향 iterator

참고 : range based for loop(범위 기반 for 구문)

for(type element : container)
{
	...
}

custom container를 사용할 경우 iterator처럼 작동하는 값을 반환하는 begin, end가 구현되어 있어야 사용 가능

Reference : https://stackoverflow.com/a/31457319/8106257

container<pointer>

주의사항

find, compare 등 algorithm을 사용할 때 만약 container가 pointer를 담고 있다면 pointer 주소값을 비교하므로 _if 접미사가 붙은 함수와 predicate를 함께 사용해야 함
erase, clear 등 container의 element를 지우는 함수를 사용할 경우 delete를 수행한 후 삭제해야 메모리 누수가 발생하지 않음 -> RAII(pointer객체는 container가 생성하지 않았음)

erase

for (auto iter = v.begin(); iter != v.end(); ++iter)
{
    v.erase(iter);
}

erase함수의 반환 값은 삭제된 element다음 값을 가리킴
iter를 통해 erase할 경우 iterator는 다음 element를 가리킴
다만, 위와 같이 이동할 경우 nullptr exception이 발생

메모리 관련 함수

int main
{
    vector<int> v;
    v.reserve(2);

    vector<int> v1(2);

    vector<int> v2;
    v2.resize(2);
}

생성자, resize를 통해 메모리를 확보할 경우 초기화되어 생성, 할당이 완료 됨
reserve를 통해 메모리를 확보할 경우 할당되지는 않음
reserve에 push_back할 경우 0번 index부터 값 할당
크고 많은 객체를 container에 보관할 경우 reserve를 통해 재할당 비용을 낮출 수 있음

많이 쓰는 함수

assign

container_constructor(count, value)

와 같은 역할

container_constructor(other_container_iterator, other_container_iterator)

를 통해 범위를 지정할 수 있음

emplace

container에서 direct하게 객체를 생성할 수 있음
불필요한 복사, 이동을 수행하지 않음
만약, 메모리를 미리 확보하지 않았다면 emplace를 수행하더라도 재할당으로 인해 효율이 떨어질 수 있음

참고 : https://modoocode.com/228#page-heading-6

이곳에서는 push_back도 emplace_back과 마찬가지로 컴파일러에서 최적화가 수행되어 불필요한 copy, move가 수행되지 않는다고 했지만, 실험결과 여전히 copy, move가 수행 됨

int main()
{
    vector<Test> v;
    v.reserve(10);
    v.push_back(1);
    v.push_back(Test(1));
    v.emplace_back(1);
}

int main()
{
    vector<Test*> v1;
    v1.push_back(new Test(1));
    v1.emplace_back(new Test(1));
}

emplace(new)를 수행해도 복사, 이동이 수행되지 않음.(완벽한 전달)

Reference : https://modoocode.com/228#page-heading-6
int main()
{
    std::vector<std::vector<int>> vec;
    vec.push_back(10);		//compile error
    vec.emplace_back(10);	//공간이 10개인 vector가 생성되어 vec에 들어감 
}

emplace의 경우 어떤 생성자가 호출되는지 명확하지 않음

참고
int main
{
    for (auto iter = v.begin(); iter != v.end(); ++iter)
    {
        v.emplace(iter, 1);	//nullptr exception
    }
}

emplace나 insert나 재할당 받은 메모리 공간의 크기에 따라 iterator를 무효화시키기도 하는데, 이 조건을 엄밀하게 제어할 수 없으므로 그냥 한번만 사용하자

splice

밧줄을 잇다, 붙이다의 뜻
다른 container의 값을 옮기는 함수

set, multiset

중복 허용 여부
기본적으로 오름차순 정렬
표준이 결정된 것은 아니지만 GCC의 경우 BST(RB Tree)로 구현됨

unordered_set

Hash를 통해 구현됨

map, multimap

중복 허용 여부
기본적으로 오름차순 정렬
표준이 결정된 것은 아니지만 GCC의 경우 BST(RB Tree)로 구현됨
전반적으로 algorithm.h의 함수들에는 사용할 수 없는것으로 보임

unordered_map

Hash를 통해 구현됨

Algorithm

algorithm이 지원하는 함수보다 STL에서 자체적으로 지원하는 함수가 더 빠름
container의 element를 수정하는지 여부를 중요하게 확인해야 함

_if, _copy 접미사

bool comp(int i) { return i == 5; }
class compClass
{
public:
    bool operator()(int i) { return i == 5; }
};

int main()
{
    vector<int> v;
    v.push_back(1);
    v.push_back(2);
    v.push_back(3);
    v.push_back(4);
    v.push_back(5);

    auto iter = count_if(v.begin(), v.end(), comp);
    auto iter1 = count_if(v.begin(), v.end(), compClass{});

    return 0;
}

predicate를 요구하는 객체는 함수, 객체 상관 없음
Lambda함수도 가능

sort

    sort(SortedContainer.begin(), SortedContainer.end(), CompClass());
    sort(SortedContainer.begin(), SortedContainer.end(), CompFunc);

범위 지정

find

    Container<Template>::iterator iter2 = find_if(Container.begin(), Container.end(), CompClass());
    Container<Template>::iterator iter2 = find_if(Container.begin(), Container.end(), CompFunc);

copy

    copy(CopiedContainer.begin(), CopiedContainer.end(), std::back_inserter(CopyContainer));

back_inserter가 필요
또는 iterator를 통한 copy가 가능한 듯

Reference : https://en.cppreference.com/w/cpp/algorithm/copy

generate

    generate(Container.begin(), Container.end(), FuncObject);

특정 범위의 원소를 함수객체의 반환값으로 채움

merge

    merge(Container1BeginIteartor, Container1EndIteartor, Container2BeginIteartor, Container2EndIterator, std::back_inserter(ResultContainer));

정렬된 두 Container를 Merge정렬하면서 ResultContainer에 복사

transform

	transform(BeginIterator, EndIterator, back_inserter(ResultContainer), FunctionObject);
    transform(Container1BeginIterator, Container1EndIterator, Container2BeginIterator, back_inserter(ResultContainer), FunctionObject);

Container의 각 Element를 수정하여 ResultContainer에 저장

    std::transform(ContainerBeginIterator, ContainerEndIterator, back_inserter(SameContainer), FunctionObject);


이 경우 무한루프가 발생하지는 않지만, Garbage값이 입력

함수 객체

class Class
{
public:
    returnType operator()(type param, ...) { ... }
};

연산자 재정의를 지원하는 모든 객체는 함수 객체
functional.h에 존재하는 객체

Reference : https://en.cppreference.com/w/cpp/header/functional

이와 별개로

function<type>

형태의 Callable을 모두 담을 수 있는 객체도 있음

Reference : https://modoocode.com/254#page-heading-0

Lambda를 쓰는 이유

위와 같은 경우 FunctionObject를 전달하기 위해 새롭게 함수를 정의하거나 Class, Struct를 정의하는 것 보단 간편하게 함수 객체를 생성할 수 있음

가변인자

C

ReturnType functionName(int count, ...) { ... }

C++

ReturnType functionName(type ...) { ... }
#include <cstdarg>

#define va_start
#define va_arg
#define va_end
#define va_copy

위 define을 이용해 인자에 접근

C++ Template

template<typename ... Types>
ReturnType functionName(Types ... args) { ... }
Reference : https://modoocode.com/290
profile
이상을 길잡이 삼아 로망을 추구합니다.

0개의 댓글