본문 바로가기
SWE/C++ OOP

std::map 올바르게 사용하기 | 아이템 삭제 방법

by S나라라2 2022. 12. 29.
반응형

std map 올바른 사용법

std::map<int, Class *> map 을 사용할 때 생각보다 어이없는 부분에서 문제가 발생한다. 

쉽게 생각하고 넘기지만 프로그램이 종료되기도 하기 때문에 정확히 알고 사용하는 것이 중요하다.

 

 

 

결론 요약 정리

 

- insert를 할 때 : 
     틀린 방법: map.at(key)= new A()
     옳은 방법: map[key] = new A()

 

-> 위의 틀린 방법으로 아이템을 추가할 경우, at 은 내부적으로 바운더리 체크가 있기 때문에 out of range exception이 발생하게 된다. at()은 아이템에 접근할 때만 사용한다.

-> operator[ ]는 아이템에 접근하고 추가할 때 모두 사용할 수 있다.

 


- 삭제할 때:
     틀린 방법: 

delete map[key]
     옳은 방법:

auto value = map[key]

delete value

map.erase(key)

 

-> delete map[key]를 하면 해당 주소의 객체가 삭제되긴 하지만 map에서 위치 주소를 여전히 저장하고 있다. 따라서 아이템을 확인하면 존재하는 걸로 나오게 된다.

 


- 존재 확인할 때:
     틀린 방법: map.find(key) != map.end()
     옳은 방법: map.contains(key) (c++20)

 

-> contains는 c++20버전부터 지원한다. 따라서 하위 버전일 경우 map[key]로 존재 여부를 확인할 수도 있다.

 


 

테스트 방법

#include <iostream>
#include <map>

using namespace std;

class A {
 public:
    A(std::string str){
        this->str_ = str;
    };
    ~A() {
    };
    std::string str_;
};

void print_map(std::string_view comment, std::map<int, A*> m)
{
    std::cout << comment;
    // iterate using C++17 facilities
    for (const auto& [key, value] : m)
        std::cout << '[' << key << "] = " << value << "; ";
    std::cout << '\n';
}

int main()
{
    std::cout << "Hello Deleting a Item of Map World" << std::endl;

    std::map<int, A*> map_;
    
    map_[0] = new A("test 0");
    map_[1] = new A("test 1");
    map_[2] = new A("test 2");
    map_[3] = new A("test 3");
    
    // map의 item 삭제 방법 1
    std::cout << "==================== Way1. delete map[n] ====================" << std::endl;
    auto p0 = map_[0];
    delete map_[0];
    if (map_[0]) {
        std::cout << "'delete map[0]' and 'map[0]' doesn't work." << std::endl;
    } else {
        std::cout << "'delete map[n]' and 'map[0]' works." << std::endl;
    }
    if (map_.find(0) != map_.end()) {
        std::cout << "'delete map[n]' and 'map.find(0)' doesn't work." << std::endl;
    } else {
        std::cout << "'delete map[n]' and 'map.find(0)' works." << std::endl;
    }
    
    if (p0) {
        std::cout << "'delete map[0]' doesn't work. object p[0] exists" << std::endl;
    }else {
        std::cout << "'delete map[0]' works. object p[0] dosen't exist" << std::endl;
    }
    
    // map의 item 삭제 방법 2
    std::cout << "==================== Way2. map.erase(n) ====================" << std::endl;
    auto p1 = map_[1];
    map_.erase(1);
    if (map_[1]) {
        std::cout << "'map_.erase(1)' and 'map[1]' doesn't work." << std::endl;
    } else {
        std::cout << "'map_.erase(1)' and 'map[1]' works." << std::endl;
    }
    if (map_.find(1) != map_.end()) {
        std::cout << "'map_.erase(1)' and 'map.find(1)' doesn't work." << std::endl;
    } else {
        std::cout << "'map_.erase(1)' and 'map.find(1)' works." << std::endl;
    }
    
    if (p1) {
        std::cout << "'map_.erase(1)' doesn't work. object p[1] exists" << std::endl;
        std::cout << "p1=" << p1->str_ << std::endl;
    }else {
        std::cout << "'map_.erase(1)' works. object p[1] dosen't exist" << std::endl;
    }
    
    // map의 item 삭제 방법 3
    std::cout << "==================== Way3. delete and erase ====================" << std::endl;
    auto p3 = map_[3];
    delete p3;
    p3 = nullptr;
    map_.erase(3);
    if (map_[3]) {
        std::cout << "way3 and 'map[3]' doesn't work." << std::endl;
    } else {
        std::cout << "way3 and 'map[3]' works." << std::endl;
    }
    if (map_.find(3) != map_.end()) {
        std::cout << "way3 and 'map.find(3)' doesn't work." << std::endl;
        auto iter = map_.find(3);
        std::cout << "found: " << iter->first << "," << iter->second << std::endl;  
    } else {
        std::cout << "way3 and 'map.find(3)' works." << std::endl;
    }
    
    // print
    std::cout << "==================== Print map ====================" << std::endl;
    print_map("", map_);
    /*for(auto iter = map_.begin(); iter != map_.end(); iter++)
    {
         std::cout << "("<< iter->first << "," << iter->second << ")"<< endl;
    }*/

    return 0;
}

 

테스트 결과

반응형