월 24,200원
5개월 할부 시다른 수강생들이 자주 물어보는 질문이 궁금하신가요?
- 미해결홍정모의 따라하며 배우는 C++
3이 아니구요?
3:58 초 부근에서 foo(x,y+1);인데 y=2이니까 2+1해서 3이 전달되는거 아닌가요????
- 미해결홍정모의 따라하며 배우는 C++
27분 05초 부근 질문있습니다.
divide & conquer 전략으로 lockguard를 쓰는 thread, atomic 쓰는 thread, promise 쓰는 thread 이렇게 만드는 건데 애초에 divide & conquer 전략이 무엇인지도 잘 모르겠고 코드를 배운대로 짠 거 같은데 자꾸 오류가 나서 막막합니다. 도움을 조금 주시면 감사하겠습니다. 밑에는 제가 짠 코드입니다.// 여태까지 멀티 스레딩을 사용하는 여러가지 문법들을 배워봤다. // 이번에는 멀티 스레딩으로 벡터 내적을 계산하는 예제를 통해서 실제 문법이 어떻게 사용이 되는 지 그리고 차이가 어떻게 나는 지 등등을 한 번 직접 실험하면서 살펴본다. #include <iostream> #include <chrono> #include <mutex> #include <random> #include <thread> #include <utility> #include <vector> #include <atomic> #include <future> #include <numeric> // std::inner_product #include <execution> // parallel execution using namespace std; mutex mtx; // mutex를 꼭 전역 변수로 선언할 필요는 없다. 여러 개의 스레드가 공통적으로 접근할 수 있는 scope에 있으면 된다. // 그리고 mutex도 항상 존재할 필요는 없다. mutex로 lockguard를 만들어주고 싶은 부분이 작동할 때만 mutex가 살아있으면 된다. // 그러니깐 코딩할 때 mutex를 어떤 클래스의 멤버로 집어넣어도 되고 scope에 넣어도 된다. void dotProductNaive(const vector<int>& v0, const vector<int>& v1, const unsigned i_start, const unsigned i_end, unsigned long long& sum) { for (unsigned i = i_start; i < i_end; ++i) sum += v0[i] * v1[i]; } void dotProductLock(const vector<int>& v0, const vector<int>& v1, const unsigned i_start, const unsigned i_end, unsigned long long& sum) { //std::scoped_lock lock(mtx); // 속도를 높이기 위해 scoped_lock을 for문 밖으로 옮기면 어떨까라고 생각할 수 있다. // scoped_lock이 작동하는 범위를 scope 전체가 되도록 옮기니깐 속도가 오히려 훨씬 빨라졌다. // 그러면 오히려 밖으로 빼면 되나 생각할 수 있는데 지금 cout으로 출력된 값을 보니깐 start, end, start, end, ... 이렇게 나왔다. // 이 전체가 lock이기 때문에 병렬이 아니라, 동시적으로 실행이 된 게 아니라 순차적으로 실행이 됐다는 의미이다. // 실제로 이런 방식으로 병렬처리를 하는 것은 의미가 없다는 거다. // 오히려 스레드를 생성하는 오버헤드만 커지게 된다. cout << "Thread start " << endl; for (unsigned i = i_start; i < i_end; ++i) { std::scoped_lock lock(mtx); // C++ 17 // 초반에 말했었지만 scoped_lock은 영역이 작은 쪽에 들어가는게 좋은데 작은 영역에 들어오긴 했지만 너무 빈번하게 자주 실행이 되어버리면 오히려 느려진다. // 멀티 스레딩을 안 하느니만 못하는 최악의 결과가 나오게 된다. 그래서 멀티 스레딩을 처음 시도를 하는 경우에는 오히려 퍼포먼스가 떨어지거나 혹은 퍼포먼스는 안 떨어지는 대신에 결과가 나쁘거나 이런 식으로 작동이 될 수 있다. // 그런데 이것도 경우에 따라서 또 다르다. 락이 걸린 scope 전후로 어마어마하게 일이 많으면 상대적으로 멀티 스레딩의 효율이 높아지기도 하는데 일단은 극단적인 경우를 가지고 실수를 할 수 있는 부분에 대해서 먼저 설명을 했다. sum += v0[i] * v1[i]; } cout << "Thread end " << endl; } void dotProductAtomic(const vector<int>& v0, const vector<int>& v1, const unsigned i_start, const unsigned i_end, atomic<unsigned long long>& sum) { for (unsigned i = i_start; i < i_end; ++i) { sum += v0[i] * v1[i]; // atomic 연산이 일반연산보다 느리기 때문에 빈번하게 호출되는 곳에 atomic 연산을 넣어버리면 느려진다. } } auto dotProductFuture(const vector<int>& v0, const vector<int>& v1, const unsigned i_start, const unsigned i_end) { int sum = 0; // local sum for (unsigned i = i_start; i < i_end; ++i) { sum += v0[i] * v1[i]; } return sum; } int main() { /* v0 = { 1, 2, 3 } v1 = { 4, 5, 6 } v0_dot_v1 = 1*4 + 2*5 + 3*6; */ const long long n_data = 100'000'000; const unsigned n_threads = 4; /* initialize vectors */ std::vector<int> v0, v1; v0.reserve(n_data); v1.reserve(n_data); // reserve()로 push할 때의 효율을 높였다. random_device seed; mt19937 engine(seed()); uniform_int_distribution<> uniformDist(1, 10); for (long long i = 0; i < n_data; ++i) { v0.push_back(uniformDist(engine)); v1.push_back(uniformDist(engine)); } cout << "std::inner_product" << endl; { const auto sta = chrono::steady_clock::now(); const auto sum = std::inner_product(v0.begin(), v0.end(), v1.begin(), 0ull); // auto인데도 unsigned long long으로 자동 추론을 할 수 있게 된 이유는 0을 0ull으로 표기를 해서 넣어줬기 때문이다. const chrono::duration<double> dur = chrono::steady_clock::now() - sta; cout << dur.count() << endl; cout << sum << endl; cout << endl; } // 멀티 스레딩 프로그래밍을 한다면 정답을 계산을 하고 그것과 정답이 맞는지 비교하고 그리고 퍼포먼스를 또 비교하는 방식으로 작업을 하는 것이 좋다. cout << "Naive" << endl; { const auto sta = chrono::steady_clock::now(); unsigned long long sum = 0; vector<thread> threads; threads.resize(n_threads); const unsigned n_per_thread = n_data / n_threads; // assumes remainder = 0 for (unsigned t = 0; t < n_threads; ++t) threads[t] = std::thread(dotProductNaive, std::ref(v0), std::ref(v1), t * n_per_thread, (t + 1) * n_per_thread, std::ref(sum)); for (unsigned t = 0; t < n_threads; ++t) threads[t].join(); const chrono::duration<double> dur = chrono::steady_clock::now() - sta; cout << dur.count() << endl; cout << sum << endl; cout << endl; } // 스레드 개수를 임의의 개수로 사용할 수 있게 하기 위해서 조금 코드가 복잡해졌다. // 실행해보면 시간도 더 걸렸고 무엇보다 답이 틀리게 나온다. 레이스 컨디션 때문에 그렇다. // sum에다가 값을 더하고 있는데 여러 개의 스레드가 동시에 값을 건드리니깐 문제가 생겨서 값이 제대로 더해지지 않고 있다. cout << "Lockguard" << endl; { const auto sta = chrono::steady_clock::now(); unsigned long long sum = 0; vector<thread> threads; threads.resize(n_threads); const unsigned n_per_thread = n_data / n_threads; // assumes remainder = 0 for (unsigned t = 0; t < n_threads; ++t) threads[t] = std::thread(dotProductLock, std::ref(v0), std::ref(v1), t * n_per_thread, (t + 1) * n_per_thread, std::ref(sum)); for (unsigned t = 0; t < n_threads; ++t) threads[t].join(); const chrono::duration<double> dur = chrono::steady_clock::now() - sta; cout << dur.count() << endl; cout << sum << endl; cout << endl; } cout << "Atomic" << endl; { const auto sta = chrono::steady_clock::now(); atomic<unsigned long long> sum = 0; vector<thread> threads; threads.resize(n_threads); const unsigned n_per_thread = n_data / n_threads; // assumes remainder = 0 for (unsigned t = 0; t < n_threads; ++t) threads[t] = std::thread(dotProductAtomic, std::ref(v0), std::ref(v1), t * n_per_thread, (t + 1) * n_per_thread, std::ref(sum)); for (unsigned t = 0; t < n_threads; ++t) threads[t].join(); const chrono::duration<double> dur = chrono::steady_clock::now() - sta; cout << dur.count() << endl; cout << sum << endl; cout << endl; } cout << "Future" << endl; { const auto sta = chrono::steady_clock::now(); unsigned long long sum = 0; vector<std::future<int>> futures; // unsigned long long으로 받지 않은 이유는 부분의 합은 integer 범위 안에 들어오기 때문이다. futures.resize(n_threads); const unsigned n_per_thread = n_data / n_threads; // assumes remainder = 0 for (unsigned t = 0; t < n_threads; ++t) futures[t] = std::async(dotProductFuture, std::ref(v0), std::ref(v1), t * n_per_thread, (t + 1) * n_per_thread); // 전역 변수 역할을 하는 sum이 들어갈 필요가 없다. 왜냐하면 dotProductFuture()에서는 local sum을 계산해서 return 해주고 있기 때문이다. for (unsigned t = 0; t < n_threads; ++t) sum += futures[t].get(); // .join()을 하는 대신에 .get()을 받아서 sum에다가 더해주고 있다. const chrono::duration<double> dur = chrono::steady_clock::now() - sta; cout << dur.count() << endl; cout << sum << endl; cout << endl; } // future 쓰는게 무조건 좋구나 thread 나빠 이렇게 생각할 수도 있다. 그런데 꼭 그렇진 않다. //TODO: use divide and conquer strategy for std::thread, std::thread & std::atomic //TODO: use divide and conquer strategy for std::thread & std::promise /* divide and conquer strategy for lockguard */ cout << "Divide Lockguard" << endl; { const auto sta = chrono::steady_clock::now(); vector<unsigned long long> divide_sum; divide_sum.resize(n_threads); vector<thread> threads; threads.resize(n_threads); const unsigned n_per_thread = n_data / n_threads; // assumes remainder = 0 for (unsigned t = 0; t < n_threads; ++t) threads[t] = std::thread(dotProductLock, std::ref(v0), std::ref(v1), t * n_per_thread, (t + 1) * n_per_thread, std::ref(divide_sum[t])); for (unsigned t = 0; t < n_threads; ++t) threads[t].join(); unsigned long long sum = 0; for (unsigned t = 0; t < n_threads; ++t) sum += divide_sum[t]; const chrono::duration<double> dur = chrono::steady_clock::now() - sta; cout << dur.count() << endl; cout << sum << endl; cout << endl; } /* divide and conquer strategy for atomic */ cout << "Divide Atomic" << endl; { const auto sta = chrono::steady_clock::now(); vector<atomic<unsigned long long>> divide_sum; divide_sum.resize(n_threads); vector<thread> threads; threads.resize(n_threads); const unsigned n_per_thread = n_data / n_threads; // assumes remainder = 0 for (unsigned t = 0; t < n_threads; ++t) threads[t] = std::thread(dotProductAtomic, std::ref(v0), std::ref(v1), t * n_per_thread, (t + 1) * n_per_thread, std::ref(divide_sum[t])); for (unsigned t = 0; t < n_threads; ++t) threads[t].join(); unsigned long long sum = 0; for (unsigned t = 0; t < n_threads; ++t) sum += divide_sum[t]; const chrono::duration<double> dur = chrono::steady_clock::now() - sta; cout << dur.count() << endl; cout << sum << endl; cout << endl; } /* divide and conquer strategy for promise */ cout << "Promise" << endl; { const auto sta = chrono::steady_clock::now(); unsigned long long sum = 0; vector<std::promise<int>> proms; proms.resize(n_threads); vector<std::future<int>> futures; futures.resize(n_threads); vector<thread> threads; threads.resize(n_threads); const unsigned n_per_thread = n_data / n_threads; // assumes remainder = 0 for (unsigned t = 0; t < n_threads; ++t) { futures[t] = proms[t].get_future(); threads[t] = std::thread([&](std::promise<int>&& prom) { prom.set_value(dotProductFuture(std::ref(v0), std::ref(v1), t* n_per_thread, (t + 1)* n_per_thread)); }, std::move(proms[t])); } for (unsigned t = 0; t < n_threads; ++t) sum += futures[t].get(); for (unsigned t = 0; t < n_threads; ++t) threads[t].join(); const chrono::duration<double> dur = chrono::steady_clock::now() - sta; cout << dur.count() << endl; cout << sum << endl; cout << endl; } cout << "std::transform_reduce" << endl; { const auto sta = chrono::steady_clock::now(); //const auto sum = std::transform_reduce(std::execution::seq, v0.begin(), v0.end(), v1.begin(), 0ull); const auto sum = std::transform_reduce(std::execution::par, v0.begin(), v0.end(), v1.begin(), 0ull); const chrono::duration<double> dur = chrono::steady_clock::now() - sta; cout << dur.count() << endl; cout << sum << endl; cout << endl; } // std::inner_product의 병렬 버전이 std::transform_reduce()이다. std::transform_reduce() 말고도 std::sort() 같은 함수들이 전부 병렬 처리를 지원해준다. 그래서 기본적인 것들을 빠르게 구현할 때는 병렬 처리를 직접 구현할 필요는 없다. // 하지만 병렬 처리 함수들을 사용하기에 앞서 멀티 스레딩을 먼저 조금 알고 있으면 사용할 때 조금 더 유리할 거고 둘째로 std에서 만들어준 코드들이 모든 문제들을 전부 병렬 처리 해주지는 않는다. 그리고 여전히 병렬 처리했을 때 문제가 생길 여지가 분명히 존재한다. return 0; }
- 미해결홍정모의 따라하며 배우는 C++
정리
제가 이해한게 맞을까요?
- 미해결홍정모의 따라하며 배우는 C++
안녕하세요. getter함수에 대해 질문이 있습니다.
교수님께서는 const int& getDay(){return m_day;} 로 멤버변수인 m_day를 리턴하셨는데, main함수에서 출력할 때는 그냥void getDay(){cout<<day<<endl;}로 public함수를 만들고, 메인에서 today.getDay();로 해줘도 되지 않나요?가령, getDate()같이 멤버변수들을 모두 출력한다고 하였을 때는cout<<month<<" "<<day<<" '<<year<<endl;로 하는 것이 편리하지 않나요??
- 미해결홍정모의 따라하며 배우는 C++
Ellipsis 강의 중 코드 동작 과정에 대해 질문이 있습니다.
교수님께서 작성하신 코드의 동작 원리가 궁금해서 디버깅으로 하나하나 파악하고 있는데, va_start 매크로 실행부분에서 list에 1 "x1"이라고 첫번째 가변인수가 저장되있더라구요? 그리고 for문 시작부분에서 arg=0 일 때, va_arg 매크로가 동작하면서 list에 2 "x2"라고 이미 접근해 있습니다. 그 다음에는 첫번째 가변인수를 저장한 1이 sum에 저장되구요. 제가 궁금한 것은,매크로가 for문보다 빨리 동작되는 건가요? arg < 3 까지 계속 증가하면서 sum을 업데이트해주니 findAverage(3, 1, 2, 3)에서 생략된 가변 인수를 배열처럼 인덱스로 생각해도 되나요? 이를테면 1을 [0], 2를 [1], 3을 [2]로 말이죠findAverage(10, 1, 2, 3, 4, 5)가 지수함수가 포함되서 나오는 이유는 가변인수에 없는 쓰레기 값을 계속해서 sum에 더해서 그렇게 나오는 건가요?
- 미해결홍정모의 따라하며 배우는 C++
int형 변수 배열에 대한 포인터에.....
int형 포인터에 int형 배열에 대한 주소를 넣고 포인터에 [0],[1] 을 입력하면 해당 배열에 대한 주소가 나오는 건가요?
- 미해결홍정모의 따라하며 배우는 C++
디버거가 이상하게 작동해요.
Copy Constructor 설명해주시는 부분 코드를 따라치고 디버거를 돌려봤는데요.이렇게 Something something;에서 Step into (F11)를 누르면 클래스로 들어가져야 하는데 그러지 않고이런 화면이 뜨는데 왜 그런 걸까요...?마찬가지로 print(something);에서 Step into를 누르면또 이런 화면이 뜨면서 안으로 안들어가져요...어떻게 하면 이 문제가 해결되는지 혹시 알려주실 수 있을까요?
- 미해결홍정모의 따라하며 배우는 C++
강의를 듣다보면 특정 시간대의 영상이 반복됩니다.
안녕하세요.강의를 듣다보면 특정 시간대의 영상이 끊기거나 반복되는데요. 이 강의에서는 11분 35초에서 영상이 끊기고 한 5~10초 전의 영상이 다시 나와요. 이게 제 컴퓨터의 문제일까요 아니면 편집이 잘못된 걸까요? 생각보다 너무 자주 이런 문제가 발생하는데 뭔가 문제인지 궁금하고 해결할 수는 없는지 궁금합니다...
- 해결됨홍정모의 따라하며 배우는 C++
피보나치 수열 연습문제 코드 리뷰 부탁드립니다!
- 학습 관련 질문을 남겨주세요. 상세히 작성하면 더 좋아요! - 먼저 유사한 질문이 있었는지 검색해보세요. - 서로 예의를 지키며 존중하는 문화를 만들어가요. - 잠깐! 인프런 서비스 운영 관련 문의는 1:1 문의하기를 이용해주세요.출력은 잘 되는데, 맞게 한건지는 잘 모르겠습니다. 다른 학생들이 한걸 보면 입력 함수 출력 함수를 따로 만들어서 깔끔하게 문제를 풀었던데, 저는 함수 하나로 입출력을 다 하게 만들어서 좀 길고 복잡하네요. 출력은 잘 됩니다만... 부족한 부분이 있는지 리뷰 좀 부탁드려도 될까요?
- 미해결홍정모의 따라하며 배우는 C++
피보나치 수열 연습문제 풀이과정입니다.
수열의 점화식을 재귀함수로 만들 수 있는 건 정말 신기하네요!! 인덱싱을 고려해서 0부터 출력해보았습니다그런데 궁금한 것이 있습니다. 재귀함수도 함수의 일종이니까 값의 복사를 방지하기 위해 매개변수에 const int&를 넣어도 무방하나요?항상 양질의 강의를 제공해주셔서 감사합니다 :)
- 미해결홍정모의 따라하며 배우는 C++
함수 포인터 check_fnc에 관해 질문이 있습니다.
#include <iostream>#include <array>using namespace std;bool isEven(const int& number){ if (number % 2 == 0) return true; else return false;}bool isOdd(const int& number){ if (number % 2 != 0) return true; else return false;}void printNumbers(const array<int, 10>& my_array, bool (*check_fnc)(const int&)=isEven){ for (auto element : my_array) { if (check_fnc(element) == true) cout << element << " "; } cout << endl;}int main(){ std::array<int, 10> my_array = { 0,1,2,3,4,5,6,7,8,9 }; printNumbers(my_array); printNumbers(my_array, isOdd); return 0;}에서 if (check_fnc(element) == true)부분인데요, check_fnc가 함수 포인터고 이것이 함수의 주소를 저장하니까 isEven으로 기본값을 설정하면, 포인터가 isEven으로 찾아가서 함수를 호출하는 것이 맞나요?그리고 printNumbers(my_array, isOdd)부분에서는 check_fnc가 isOdd의 주소를 저장했으니까if (check_fnc(element) == true)의 check_fnc가 isOdd를 호출하는 것도 맞나요??
- 미해결홍정모의 따라하며 배우는 C++
제가 한 선택정렬 코드 리뷰 좀 부탁드려도 될까요?
- 학습 관련 질문을 남겨주세요. 상세히 작성하면 더 좋아요! - 먼저 유사한 질문이 있었는지 검색해보세요. - 서로 예의를 지키며 존중하는 문화를 만들어가요. - 잠깐! 인프런 서비스 운영 관련 문의는 1:1 문의하기를 이용해주세요.안녕하세요.수업에서 나온 선택 정렬을 제가 만들어보고 선생님께서 한 것과 비교를 해봤는데요.제가 한 건 선생님께서 하신 것 보다 좀 더 복잡하고 쓸대없는 과정이 추가되어 있는 것 같아요.이거는 작은 코드니까 별 상관없지만, 나중에 프로그램이 커지면 불필요한 요소들 때문에 최적화(?) 같은거에 방해가 될 요소가 좀 있는 것 같은데,코드리뷰를 한 번 부탁드려도 될까요?
- 미해결홍정모의 따라하며 배우는 C++
15.5 unique_ptr return
auto doSomething2(std::unique_ptr<Resource> res){ res->setAll(10); return res;}...int main(){... res1 = doSomething2(std::move(res1));}이부분에서 res1를 R-value로 전환하여 doSomething2함수의 파라미터인 L-value res에 주소의 소유권을 넘겨준 것 까진 이해했습니다,그리고 doSometing의 함수가 끝나면 res라는 unique_ptr 변수는 해제되는 거 아닌가요?? 해제 된 변수를 return 해서 사용해도 괜찮은건가요??
- 미해결홍정모의 따라하며 배우는 C++
vscode 헤더파일 포함 및 링크 방법 문의
사정상 강의를 맥으로 따라가고 있습니다. vscode 사용시 헤더파일과 링크에대한 기존 질문과 답변을 확인하였으나 초보인관계로 makefile에 대한 링크를 확인했지만 해결을 못했습니다.vscode로 헤더를 추가하고 파일을 링크시킬수있는 자세한 설명을 안내해주시면 정말 정말 감사하겠습니다
- 미해결홍정모의 따라하며 배우는 C++
9.12 이니셜라이저리스트 연습문제
#include <iostream>#include<cassert>using namespace std;#include<initializer_list> class IntArray{ unsigned mLength = 0; int *mData = nullptr;public: IntArray(unsigned length) : mLength(length) { mData = new int[length]; } ~IntArray() { delete[]this->mData; } IntArray(const std::initializer_list<int> &list): IntArray(list.size()){ int count = 0; for ( auto &e : list ) { mData[count] = e; ++count; } } friend ostream &operator<<(ostream &os, IntArray &arr) { for ( unsigned i = 0; i < arr.mLength; ++i ) { os << arr.mData[i] << " "; } os << endl; return os; } //=operator IntArray& operator=(const std::initializer_list<int> &array) { cout << "assignment operator" << endl; delete[] mData; mLength = array.size(); if(mData!=nullptr ) { mData = new int[mLength+1];//이 부분에서 mData = new int[mLength];로 코딩하면 버퍼 오버런이 뜹는데 오류 메세지를 보면이렇게 나옵니다 0에서 0사이라는 것이 뭔가요?? int i {}; for ( auto &e : array ) { mData[i++] = e; } } else { mData = nullptr; } return *this; }}; int main(){ IntArray intArray = {11,12,13,14,15,16,17,18,19,20}; intArray = {1,2,3,4,5,6,7,8,9,10}; cout << intArray << endl;}
- 미해결홍정모의 따라하며 배우는 C++
제가 알고 있는게 맞는지 훈수좀요!!
ignore()함수는 cin연산자?? 의 구성요소 중 하나이고 cin은 std에 정리 되어 있으며 이 std는 iostream이라는 라이브러리(도서관)에 정의 되어 있다......!라고 하면 되는 건가요 그리고 ignore(x,y)는 x까지 입력을 받거나 y를 만나면 그 이후는 무시하라! 라고 이해하면 되는 거죠? 그리고 지금 드는 의문인데요 using namespace std;를 사용하고 있는데 ignore()이랑 fail()은 왜 앞에 std::cin을 붙여줘야 하죠?
- 미해결홍정모의 따라하며 배우는 C++
9.12 연습문제 대입연산자 오버로딩
class IntArray{unsigned mLength = 0;int *mData = nullptr;public:IntArray(unsigned length): mLength(length){mData = new int[length];}~IntArray(){delete[]this->mData;}IntArray(const std::initializer_list<int> &list): IntArray(list.size()){int count = 0;for ( auto &e : list ){mData[count] = e;++count;//count++로 쓰기도 함}}//=operatorIntArray& operator=(const std::initializer_list<int> &array){cout << "assignment operator" << endl;delete[] mData;mLength = array.size();if(mData!=nullptr ){mData = new int[mLength];int i {};for ( auto &e : array ){mData[i++] = e;}}else{mData = nullptr;}return *this;}};int main(){intArray2 = {1,2,3,4,5,6,7,8,9,10};cout << intArray << endl;}이런식으로 작성을 했는데 버퍼오버런이나옵니다버퍼오버런이 사이즈가 m-1개인데 더 큰 데이터를 넣을 할 때 발생? 하는 거라고 검색해서 찾았는데 size()함수는 배열 갯수 -1을 반환하는 것은 아닌거 같은데.. https://learn.microsoft.com/ko-kr/cpp/standard-library/initializer-list-class?view=msvc-170 //=operatorIntArray& operator=(const std::initializer_list<int> &array){cout << "assignment operator" << endl;delete[] mData;mLength = array.size();if(mData!=nullptr ){mData = new int[mLength+1];int i {};for ( auto &e : array ){mData[i++] = e;}}else{mData = nullptr;}return *this;}이렇게 1을 추가해주면 오버런이 발생하지 않아요왜일까요....?? 디버거를 봐도 이해가 안됩니다
- 미해결홍정모의 따라하며 배우는 C++
[3:09] 질문
ostream & out 을 사용 하시는데, 강의 상에서는 cout처럼 사용하면 된다라고 말씀하시고 넘어가셔서 궁금증이 생겼습니다.out이 뭔지, 왜 이것을 cout처럼 써도 되는건지이와 관련된 강좌가 있는지여쭙고 싶습니다. 감사합니다
- 미해결홍정모의 따라하며 배우는 C++
17.5 강의 질문있습니다.
int main() { string str1("one"); string str2; str2 = str1; //궁금한 부분. str2 = "two"; cout << str1 << endl; cout << str2 << endl; }를 했을 때 출력 값으로 str1 은 one 이 나오고 str2는 two 가 나옵니다.근데 str2 = str1; 은 얕은 복사로 서로 같은 주소를 가르킨다고 생각이 되는데얕은 복사가 되지 않은 이유는c++에서 overload로 = 을 깊은 복사로 만들어주었기 때문이라고 이해하면 될까요?아니면 다른 문법적 이유가 있어서 얕은 복사가 되지 않는 건가요?
- 미해결홍정모의 따라하며 배우는 C++
&& (R-value)와 얕은복사 개념에 대해 질문있습니다.
공부를 하다가 문뜩 깊은복사와 얕은복사 그리고 && 관련하여 궁금한 점이 생겼습니다.깊은 복사는 새로운 메모리를 생성해서 다르게 주소를 갖는다 라고 생각해서m_data = new int[m_length]; for (unsigned i = 0; i < m_length; ++i) { m_data[i] = res.m_data[i]; return *this; }m_data = new int[m_length]; 와 같이 새로운 메모리를 생성해서 res.m_data를 받도록 해주는 것입니다.하지만 얕은 복사는 새로운 메모리를 생성하지 않고 서로 같은 주소를 가르킨다 라고 생각해서int* m_data = new int[5]; m_data[1, 2, 3, 4, 5]; int* r_data = m_data; m_data[2] = 9; //9가 출력된다. std::cout << r_data[2] << std::endl;m_data 와 r_data 가 같은 주소를 가르켜서 둘이 서로 간섭하는 형태를 볼 수 있다.그렇다면Autoptr& operator = (Autoptr&& a) { std::cout << "Autoptr move assignment" << std::endl; if (&a == this) return *this; if (!m_ptr) delete m_ptr; m_ptr = a.m_ptr; a.m_ptr = nullptr; std::cout << m_ptr << std::endl; return *this; }에서 m_ptr = a.m_ptr; a.m_ptr = nullptr;은 얕은 복사인데 a.m_ptr 이 사라지면 m_ptr도 같이 사라진다 라고 생각하는 것이 아니라 a.m_ptr 만 사라져서 m_ptr 을 간섭하지 못하게 (만약 살아있으면은 a.m_ptr 로 m_ptr을 간섭할 수 있으니깐!) 만든다고 생각하는 것이 맞을까요?제가 제대로 이해했는지 궁금해져서 이렇게 길게 질문을 남겨봅니다 ㅎㅎ.. 긴 질문 봐주시느라 늘 감사합니다. (꾸벅)