본문 바로가기
3D 프로그래밍 수업(일부비공개)

심화 수업3일차 - 연결 리스트(Linked List)

by MY블로그 2023. 4. 21.

과제 : lvaue, rvalue 정리, lvaue reference 정리, rvalue reference 정리.

#include <iostream>
#include <vector>
#include <list>

using namespace std;
//연결리스트 -> 트리구조를 위해서 선행

struct A
{
    //A()
    //{
    //    cout << "생성됨 " << endl;
    //}
    ~A()
    {
        cout << "소멸됨 " << endl;
    }
    int data;

    // & 하나만있으면 lvalue , && 두개있으면 rvalue
    A&& Func() // 구조체 타입을 반환하는 (자기자신을 반환하는) 함수, 값 복사
    {
        //return *this; // 포인터를 역참조 lvalue 일때
        return A(); // 포인터를 역참조 rvalue 일떄
    }
};

//////////////////////////////연결 리스트 구현(시작)///////////////////////////////

//노드 클래스
template<typename T> // 어느자료형이든 사용 가능한 것(템플릿)
struct ListNode
{
    T data;
    ListNode* next;
};

//기능을 제공하는 클래스
template<typename T> // 어느자료형이든 사용 가능한 것(템플릿)
class LinkedList // 연결 리스트 클래스 직접만들기
{
    ListNode<T>* head;
    //void Push_back();

    //void PushFront(T data) // 복사생성 하기때문에 메모리를 추가적으로 사용한다 때문에 느리다
    //{

    //}
    //void PushFront(T& data) // 이동생성 lvalue 를 사용하기위해서 참조하기때문에 추가메모리 사용 x
    //{

    //}
    //void PushFront(T&& data) // 이동생성 rvalue 를 사용하기위해서 
    //{

    //}
    // lvalue를 rvalue 로 사용하기위해서는 &&사요하면되지만
    // rvalue를 lvalue 로 사용하기위해서는 std::move 를 사용해야 한다. (이동시멘틱)
    // 이동시멘틱사용시 기존에있던위치값이 없어지기떄문에 다음에 사용이 불가능하다! 뱅글링포인터같은느낌

    void PushFront(ListNode<T>&& data) // std::move 를 사용하기 위해서
    {

    }

};

//////////////////////////////연결 리스트 구현(끝)///////////////////////////////


int main()
{
    A val;
    // rvalue
    val = A(); // 임시객체

    // rvalue
    val.Func(); // 임시객체 이기 때문에 소멸자만 호출된다
    //val.Func().data = 3; // rvalue 라서 오류
    //A Func() 에서 A& Func() 으로 변경하면 lvalue로 변경이가능하게된다
    //val.Func().data = 3; // 위처럼 수정하고나면 가능!


    int number[5] = {0,2,3,4,5};

    //(number[3]++) = 3; // 쓰이고 버려지는 값이라 대입 불가 (반환이 되어버린값)
    //(++number[3]) = 3; // 증가되고 난 값이기때문에 대입이 가능하다 (아직 반환이 안된값)

    // rvalue (쓰이고버려지는 값 / 임시 객체)
    cout << number[3]++ << endl; // 4 출력
    // lvalue
    cout << ++number[3] << endl; // 6 출력

    //ListNode<int>(); // 임시객체 rvalue 호출과동시에 소멸됨

    // 배열은 연속적인 메모리
    // 연속적이지 않다면 시작주소로부터 접근이 불가능해지기 때문이다.
    number[3] = 2; // 배열은 0번부터 시작이기때문에 3번배열은 4번째 값이다.

    cout << number << endl; // 배열의 이름은 시작주소
    cout << *number << endl; // 역참조
    cout << *(number+2) << endl; // 역참조

    cout << "Hello World!"<< endl;
    
    vector<int> list1;
    list<int> list2;

    //list1[3]; // 벡터는 임의접근이 가능한 구조이지만
    //list2[3]; // 리스트는 임의접근이 불가능한 구조이기때문에 배열방식선언이 불가능하다.
    //리스트의 장점 = 링크된 리스트사이에 삽입 삭제를 포인터를 바꿔서 간단히가능하다.
    //이에반해 벡터(배열)은 중간에 삽입시키는것은 삽입된 뒤에 자료들이 전부한칸씩 이동해야되서
    //효율적이지 못하기떄문에 리스트를 사용한다.

    //접근 방식 두가지 for, auto
    for (int i = 0; i < list1.size(); i++)
    {
        list1[i]; // -> *(number + i) 역참조하는 방식 시작주소부터 점프하는것
        // 즉, 0번부터 몇번째에있는것을 가리키는 하나의 과정이 추가되는것
    }

    // 벡터
    for (auto it = list1.begin(); it != list1.end(); it++)
    {
        *it; // 주소를 한단계식 증가시키는 것. 즉, 가리키는 주소가 바뀌는 것
        // 0번부터 몇번째가아닌 그 주소로 바로 갈 수 있는 것
        it + 2; // 벡터는 연속적이기때문에 위치 증가가 가능하지만
    }

    // 리스트
    for (auto it = list2.begin(); it != list2.end(); it++)
    {
        *it; // 
        //it + 2; // 리스트는 비연속적이기 떄문에 위치 증가가 불가능하다!

    }

    LinkedList<int> list3; // 구현시켜 만든 연결리스트



    // 실행직후 종료되지 않게 만들어 놓은 임식 입력변수
    int a;
    cin >> a;
}

 

 

수업 코드

#include <iostream>
#include <vector>
#include <list>

using namespace std;

//stl

struct A
{
   /* A()
    {
        cout << "생성됨" << endl;

    }*/
    ~A()
    {
        cout << "소멸됨" << endl;
    }
    int data;
    //lvalue reference
    A& Func()
    {
        return *this;
    }
};

//노드
template<typename T>
struct ListNode
{
    T data;
    ListNode* next;
};

//기능을 제공하는 클래스
template<typename T>
class LinkedList
{
public:
    ListNode<T>* head;
    //void Push_back()

    void PushFront(T& data)
    {

    }
    void PushFront(ListNode<T>&& data)
    {

    }

};


int main()
{
    //LinkedList<int> aaa;
    //ListNode<int> bbb;
    //aaa.PushFront(bbb);
    //aaa.PushFront(move(bbb));


    A val;
    //   rvalue
    val = A();
    
    //   lvalue
    val.Func().data = 3;


    int number[5] = { 0,2,3,4,5 };
    
    //(number[3]++) = 3;
    //(++number[3]) = 3;

    //        rvalue (쓰이고 버려지는값)
    cout << number[3]++ << endl;
    //        lvalue
    cout << ++number[3] << endl;




    //연속적인 메모리
    //연속적이지 않으면 시작주소로부터 접근불가
  
    number[3] = 2;

    cout << number << endl;
    cout << *number << endl;
    cout << *(number +0) << endl;



    cout << "Hello World!" << endl;


    vector<int> list1;

    //list1.front() = 3;
    
    list<int> list2;
    LinkedList<int> list3;

    //list1[3]; //벡터는 임의접근 가능
    //list2[3]; //리스트는 임의접근 불가능

    for (int i = 0; i < list1.size(); i++)
    {
        list1[i];// ->  *(number + i )
    }
    for (auto it = list1.begin(); it != list1.end(); it++)
    {
        *it; // 
        it + 2;
    }
    for (auto it = list2.begin(); it != list2.end(); it++)
    {
        *it; // 
        //it + 2;
    }


    int a;
    cin >> a;
}

댓글