안녕하세요! 항상 수고 많으십니다. r-value 레퍼런스와 move 함수에 대해 궁금한 것이 몇 있는데 나름 찾아봤지만 해소되지않은 부분이 있어 이렇게 여쭤봅니다. 아래와 같이 && 를 통해 r-value 를 받고있는데요, { int && ref = 5; cout << ref << endl; //ok ref = 3; // ok cout << &ref << endl; //ok } { ref; //error, 정의된 scope 밖 } 원래 r-value 이던 5 는 잠시 레지스터든 어디에 임시 생성됐다가 표현식( ; )이 끝나면 바로 사라질 예정이었지만 l-value 로 바뀌어 메모리에 직접 저장되는 형식으로 되어, l-value 처럼 작동한다는 것이 적절한 이해인가요? (scope안에서는 계속 데이터 유효, scope 밖은 자동소멸 등..) move 함수에 대해서, move 는 인자로 들어간 것을 r-value 로 리턴하여 소유권을 이전, 및 자신의 소유권은 박탈해줍니다. 다음의 예시에서, string&& s 가 r-value 인 abc 를 받고있는데요, 이때 b 는 move(s) 를 통해 abc 에 대한 소유권을 이전받고, s 는 소유권을 박탈당해서 코드 실행시 다음의 결과가 나옵니다. b 는 abc를 정상출력, s 는 소유권을 박탈당해 아무것도 출력안함. 즉 move 가 소유권 이전, 박탈을 잘 해주는데요, 한편, (15.4강 2:54부근) 에서 가운데를 보면 res1 이 move 를 통해 r-value 로 리턴되고 res2 로 소유권(포인팅 주소) 이전 및 자신은 박탈 되는 것 처럼 보입니다. 명확히 확인해보기 위해 저 주황줄 코드가 호출하는 생성자에 아래와 같이 res1 의 m_ptr 의 주소를 찍어봤는데 와 같이 널포인터(소유권상실)가 아닌 가지고 있던 주소를 계속 가지고 있습니다. 저희가 50번째 줄에 널포인터를 직접 넣기 전에도 소유권 박탈은 안 된 모습인데 move 를 통해 소유권이 상실되는 string 케이스와는 대비가 되는 모습입니다. string 과 달리 사용자 정의 자료형은 이전이나 박탈은 사용자가 직접 정의 해줘야한다는 시각으로 이해하면 될까요? 그리고 move 를 통해 r-value 로 바뀐다고 하는데 그렇다면 바로 위의 예시에서 res1 는 r-value 가 돼서 언뜻 보면 26번줄 이후로는 소멸될 것 같지만 AutoPtr 클래스인 res1 에 테스트 멤버함수를 만들어 호출해봐도 정상적으로 작동이 됩니다. (i'am --> i'm 오타입니다) --> res1 test 멤버함수 --> 32번째 줄 test 멤버함수 호출 이것을 토대로 생각해보면 res1 에 대해 res1 자체를 r-value 로 수정하는 것이 아니라, 자신은 변경되는 것이 아닌 res1 를 r-value 로 가공한 걸 잽싸게 넘겨주고 자신은 바뀌는 것 없이 끝인 개념인가요? 의 경우 위에 해당하는 r-value 복사생성자로 이동합니다. 이렇게 얕은복사가 진행됩니다. ---------------------------------------------------- 이번에는 위에 move 함수를 뺐는데요, 그러면 에 해당하는 l-value 복사생성자가 호출됩니다. 실제로 30번 줄에 의해 와 같은 깊은복사가 일어나게 됩니다. 그래서 r-value 를 써서 소유권 이전 등으로 얕은복사로 리소스를 적게쓰자가 지향점이겠으나 그냥 단순히 아까 깊은복사가 일어나는 l-value 복사생성자 의 내용을 처럼 그냥 얕은복사가 일어나도록 하는 코드로 갈아끼우면 되는 것 아닌가요? 물론 저렇게는 오류가 나서 처럼 const 를 빼주면 정상작동합니다. 위 실행결과 --> 결과도 의도하는 얕은복사가 이루어지는데 이런 방법이 왜 잘못된 건지 알고싶습니다. 질문글이 좀 많이 길어 죄송한 면이 있네요. 항상 친절한 답변 감사합니다. 감사합니다. 3번 질문에 해당하는 코드입니다. <main.cpp> #include "AutoPtr.h" #include "Resource.h" #include <iostream> using namespace std; template<class T> void MySwap(T& a, T& b) { //T tmp = a; //a = b; //b = tmp; T tmp{ std::move(a) }; a = std::move(b); b = std::move(tmp); } int main() { { AutoPtr<Resource> res1(new Resource(1000000)); cout << res1.m_ptr << endl; AutoPtr<Resource> res2 = res1; cout << res1.m_ptr << endl; cout << res2.m_ptr << endl; } return 0; } <AutoPtr.h> #pragma once #include <iostream> using namespace std; template<class T> class AutoPtr { public: T* m_ptr; public: AutoPtr(T* ptr = nullptr) : m_ptr(ptr) { std::cout << "AutoPtr default constructor " << std::endl; } ~AutoPtr() { std::cout << "AutoPtr destructor " << std::endl; if (m_ptr != nullptr) delete m_ptr; } AutoPtr(AutoPtr& a) : m_ptr(a.m_ptr) { a.m_ptr = nullptr; // really necessary? std::cout << "AutoPtr move constructor " << std::endl; } AutoPtr& operator = (const AutoPtr& a) { std::cout << "AutoPTr copy assignment " << std::endl; if (&a == this) // prevent self-assignment return *this; if (m_ptr != nullptr) delete m_ptr; // deep copy m_ptr = new T; *m_ptr = *a.m_ptr; return *this; } AutoPtr(AutoPtr&& a) : m_ptr(a.m_ptr) { a.m_ptr = nullptr; // really necessary? std::cout << "AutoPtr move constructor " << std::endl; } AutoPtr& operator=(AutoPtr&& a) { std::cout << "AutoPtr move assignment " << std::endl; if (&a == this) return *this; if (!m_ptr) delete m_ptr; //shallow copy m_ptr = a.m_ptr; a.m_ptr = nullptr; return *this; } void test() { std::cout << m_ptr << " i'am here " << std::endl; } T& operator*() const { return *m_ptr; } T* operator->() const { return m_ptr; } bool isNull() const { return m_ptr == nullptr; } }; <Resource.h> #pragma once #include <iostream> class Resource { //private: public: int* m_data = nullptr; unsigned m_length = 0; public: Resource() { std::cout << "Resource constructed" << std::endl; } Resource(unsigned length) { std::cout << "Resource length constructed" << std::endl; this->m_data = new int[length]; this->m_length = length; } Resource(const Resource& res) { std::cout << "Resource copy constructed" << std::endl; Resource(res.m_length); for (unsigned i = 0; i < m_length; ++i) m_data[i] = res.m_data[i]; } ~Resource() { std::cout << "Resource destroyed" << std::endl; if (m_data != nullptr) delete[] m_data; } Resource& operator = (Resource& res) { std::cout << "Resource copy assignment" << std::endl; if (&res == this) return *this; if (this->m_data != nullptr) delete[] m_data; m_length = res.m_length; m_data = new int[m_length]; for (unsigned i = 0; i < m_length; ++i) m_data[i] = res.m_data[i]; return *this; } void print() { for (unsigned i = 0; i < m_length; ++i) std::cout << m_data[i] << " "; std::cout << std::endl; } void setAll(const int& v) { for (unsigned i = 0; i < m_length; ++i) m_data[i] = v; } };
안녕하세요 선생님 🙂 쉽게 설명해주셔서 항상 감사합니다 ^^ 다름이 아니라 누적합 개념강의에서 선생님께서는 아래의 방식으로 설명해주셨는데요, 0번 인덱스는 비워둠 psum배열을 전역으로 설정하여 값들을 전부 0으로 초기화 psum[1]부터 psum[i - 1] + a[i]를 하시면서 누적합을 계산 아래 방식이 효율적인지 궁금합니다. 0번 인덱스 사용 psum배열에 a배열을 복사 psum[0]은 그대로 둠 psum[1]부터 psum[i] + psum[i - 1] 아래는 선생님께서 설명해주신 승철이가 뇌를 잃어버린 문제에 대한 제 풀이의 전체 코드입니다. #include <iostream> #include <vector> #include <iterator> using namespace std; #define N 8 #define M 3 int A, B; int temp[N]; int main() { int arr[N] = { 1, 2, 3, 4, 5, 6, 7, 8 }; copy(begin(arr), end(arr), begin(temp)); for (int i = 1; i < N; i++) temp[i] += temp[i - 1]; for (int i = 0; i < M; i++) { cin >> A >> B; cout << temp[B] - temp[A - 1] << endl; } return 0; }
http://boj.kr/7effb2a3b4f44d839abcd6ebb1898979 1. 비트마스킹을 이용한 조합 구하기.2. 최소 영양소를 만족하는 조합 걸러내기.3. 그 중 최소 가격 갱신하기.4. 그때의 음식 인덱스 모으기.순으로 풀어갔는데 4에서 막혔습니다. 왜 틀린걸까요?
일단 오류를 찾아서 고쳐 정답이 맞긴 했습니다. 그런데 아무리 봐도 이해가 안돼서 질문글을 남깁니다. 고친부분은 dfs함수에 ret을 전역변수가 아닌 지역변수로 바꾼건데 전역변수로 되어있다해도 함수 시작시 초기화를 해주는데 의미가 있나요? https://www.acmicpc.net/source/76553884
주신 프로그램 중 constructSelect.cpp 에서 디폴트 생성자를 지우면 에러가 발생하는데 virtualFunction 에서는 디폴트 생성자가 없어도 동작합니다. constructSelect.cpp 에서 선언 방식이 아닌 new 연산자를 사용해서 해봐도 에러가 발생하고 객체 내에 멤버메서드가 없어서 그런가 해서 멤버를 만들어도 에러가 발생합니다 VirtualFunction 내의 소멸자의 virtual 을 제거해도 이건 잘 작동합니다. 눈으로 봐서는 도저히 차이점을 모르겠습니다.
안녕하세요. 선생님 이동 생성자 강의 내용 중 질문이 있습니다. (아래 코드 참고) delete pnData를 하면, 포인터 변수가 해제되어 pnData = rhs.pnData;를 실행할 수 없는 것이 아닌지 궁금합니다. 실재로는 포인터 값은 그대로고, 가리키는 값(int 0)만 삭제되는 것인가요? 포인터 값은 놔두고 가리키는 값만 없애는 문법은 어떻게 되나요? delete를 안하고, pnData = nullptr; 로만 수정해도 됬을 것 같습니다. class TestData { public: TestData(){ pnData = new int(0); } ... TestData(TestData&& rhs) noexcept{ delete pnData; pnData = rhs.pnData; rhs.pnData = nullptr; } ... TestData& operator=(TestData&& rhs) noexcept{ delete pnData; pnData = rhs.pnData; rhs.pnData = nullptr; } }
[C++과 언리얼로 만드는 MMORPG 게임 개발 시리즈] Part1: C++ 프로그래밍 입문
처음 메인함수에서 factorial(5)를 실행하면 팩토리얼 함수로 들어가서 return을 n * factorial(n - 1)이잖아요 그러면 5 * factorial(4)니까 함수가 다시실행되서 5 * 4 * factorial(3)이런식으로 계속 호출 되는건가요? 그리고 리턴값이 왜 120이 나오는지 조금 헷갈립니다 처음 factorial(5)를하면 5 * factorial(4)일텐데 이값을 리턴해주는게 아니고 또다시 함수가 호출되는거같은데 혹시 리턴값이왜 120이 나오는지 설명해주실 수 있으실까요 ㅠ
안녕하세요 큰돌 강사님 v[y-1][x-1].push_back(z); 로 하면 틀리는 이유를 알고 싶습니다. 입력으로 들어오는 x가 열 아닌가요?? 처음 두 개의 정수는 나무의 위치 (x, y)를 의미하고, 마지막 정수는 그 나무의 나이를 의미한다 답변 미리 감사드립니다 😄
zsh: parse error near `\n' (base) mongsil@sinjihwan-ui-MacBookAir ~ % cd /usr/local/include mkdir bits cd bits vi stdc++.h cd: no such file or directory: /usr/local/include (base) mongsil@sinjihwan-ui-MacBookAir bits % clang --version Apple clang version 14.0.3 (clang-1403.0.22.14.1) Target: arm64-apple-darwin22.5.0 Thread model: posix InstalledDir: /Library/Developer/CommandLineTools/usr/bin (base) mongsil@sinjihwan-ui-MacBookAir bits % clang++ -v Apple clang version 14.0.3 (clang-1403.0.22.14.1) Target: arm64-apple-darwin22.5.0 Thread model: posix InstalledDir: /Library/Developer/CommandLineTools/usr/bin (base) mongsil@sinjihwan-ui-MacBookAir bits % ~/Library/Application Support/Code/User/settings.json zsh: no such file or directory: /Users/mongsil/Library/Application (base) mongsil@sinjihwan-ui-MacBookAir bits % cd /usr/local/include mkdir bits cd bits vi stdc++.h cd: no such file or directory: /usr/local/include
http://boj.kr/ce16c6cbdf114d2dab3f3a8f44c9c285 안녕하세요 강사님 2-P 문제를 강사님의 풀이와는 달리 for 중첩문이랑 처음 입력한 mp배열을 복사해서 풀이할 temp배열을 만들어서 풀어봤는데 몇몇 예제에서 오답이 나와서 질문 드려요ㅠㅡ
큰돌님 안녕하세요.강의 잘 듣고 있습니다. 제 나름대로 고민해보고 풀어 제출하였는데 Segementation fault가 뜹니다.반례를 찾으려고 노력했지만 어느 부분이 문제인지 잘 모르겠습니다.도움 좀 부탁드리겠습니다 ㅠㅠ http://boj.kr/38620660c1684a9f96e362ffbdb9ebc4
- 학습 관련 질문을 남겨주세요. 상세히 작성하면 더 좋아요! - 먼저 유사한 질문이 있었는지 검색해보세요. - 서로 예의를 지키며 존중하는 문화를 만들어가요. - 잠깐! 인프런 서비스 운영 관련 문의는 1:1 문의하기를 이용해주세요. pair 정렬을 예제로 하신 거 같은데, 출력시켜봤을 때 저는 아래처럼 나오고 있습니다. 1 8 2 2 3 9 4 1 6 4 7 6 9 7 10 10 그런데 강의에는 8 2 10 1 4 6 7 10 이렇게 나와있는데.. 왜 저런 정렬결과가 나오는지 궁금합니다.
선생님, 안녕하세요. 괄호추가하기 문제를 풀어보고 있습니다. bfs는 아니고, 큐를 이용하기는 하는데 visited를 이용하지 않게 문제를 풀고 있어요. 전략은 처음에 큐에 식을 넣고, 큐에서 뺄 때, 수식을 계산한다음, 앞에서부터 괄호를 칠 수 있는 부분에 하나씩 괄호를 치고 넘기고. 이걸 반복하고 있습니다. 예를 들면, 9 3+8*7-9*2 를 입력했을 때, 3+8*7-9*2 (3+8)*7-9*2 3+(8*7)-9*2 3+8*(7-9)*2 3+8*7-(9*2) (3+8)*(7-9)*2 (3+8)*7-(9*2) 3+(8*7)-(9*2) 이런식으로 해서 모든 경우의 수를 구해서 비교하는 방식으로 하고 있는데요. 예제는 잘 통과하는데, 제출하면 틀리네요... 한번 봐주시고, 의견주시면 감사하겠습니다. 또, 어떤 반례가 있을까요?? http://boj.kr/0fced5587b8a4c5eb38406042eff5d6d 감사합니다~!
- 학습 관련 질문을 남겨주세요. 상세히 작성하면 더 좋아요! - 먼저 유사한 질문이 있었는지 검색해보세요. - 서로 예의를 지키며 존중하는 문화를 만들어가요. - 잠깐! 인프런 서비스 운영 관련 문의는 1:1 문의하기를 이용해주세요. 안녕하세요. 강의 잘듣고있습니다.! 메모이제이션 부분이 이해가 잘 안되서 질문드립니다. dp에 어떤 값이 들어가 있을 때 재귀 호출하지 않고 dp에 담겨져 있는 값을 리턴하는 것에 대한 추가 설명 가능할까요? #include <bits/stdc++.h> using namespace std; int T, W; vector<int> I; int mx = 0; int DP[1001][3][31]; // tree: 트리번호 // cnt: 움직인 횟수 int go(int idx, int tree, int cnt){ int another_tree; if (tree==1) another_tree =2; else another_tree =1; if (idx == T) return 0; // 기저사례 int &ret = DP[idx][tree][cnt]; // 메모이제이션 if (ret) return ret; if (cnt > 0) ret = max(go(idx+1, another_tree, cnt-1), go(idx+1, tree, cnt)) + (tree == I[idx]? 1:0); else ret = go(idx+1, tree, cnt) + (tree==I[idx]? 1:0); return ret; } int main(){ cin.tie(NULL); cout.tie(NULL); ios_base::sync_with_stdio(false); cin >> T >> W; I = vector<int>(T,0); for(int i =0 ; i < T; ++i){ cin >> I[i]; } cout << max(go(0, 2, W-1), go(0, 1, W)); return 0; } dp에 어떤값이 들어가있다는 것은 이미 한번 수행한 이력이 있는 정점이라는 의미로, 더 이상 아래 정점을 탐구할 필요가 없다 라는 의미겠는데.., 완전히 이해를 하지 못하여 질문드려요
안녕하세요 선생님! 항상 수업 잘 듣고 있습니다 다름이 아니라 저는 dp에 값이 있으면은 사이클이 생긴다는 가정으로 최대숫자를 반환해서 처리하였는데요. 몇 번 시도하였는데 계속 틀림이 뜨네요 ^^; http://boj.kr/56bf4bf2cf4d411fb652d50f54160a7e 그래서 선생님 답안을 보았는데 visited 배열을 따로 만드시고 나중에는 방문 미처리를 해주셨더라고요. 나중에 방문 미처리 해주시는 것이 이해가 잘 안가 왜 그렇게 해주셨는지 궁금합니다! 미리 감사드립니다~ 🙇♀
http://boj.kr/c19ff269920c4179b4e924f04e342db4 안녕하세요 강사님 2 - O 문제를 2 - N 을 보고 비슷하게 풀어보려고 하는데 자꾸 segfault가 떠서 질문 드립니다. 혹시 stk에서 stk.top () 함수가 빈 stk을 참조해서 이런 문제가 발생하나 해서 empty함수를 추가했는데도 같은 결과만 나오네요ㅠ