월 24,200원
5개월 할부 시다른 수강생들이 자주 물어보는 질문이 궁금하신가요?
- 해결됨홍정모의 따라하며 배우는 C++
강의 8:07 질문
안녕하세요. 8:07에서 반환값의 자료형이 int&이니getValue 함수 안의 value를 선언할 때도 int&로 선언해야 하는 것 아닌가요?즉, 함수의 반환값과 변수의 자료형을 맞춰야 하는 것이 아닌지 궁금합니다.
- 미해결홍정모의 따라하며 배우는 C++
5.10강 y변수 입력받을때를 고려하면 static 사용
제목에 거의다쓴거같은데int y = getInt(); 에서위에 x선언할때 썼던getInt()함수를 한번 더 사용중이니까함수 안의 int x; 선언문을static int x; 로 바꾸는게 더 좋은건지 궁금합니다.
- 미해결홍정모의 따라하며 배우는 C++
STL 반복자에서 end() 가리키는 게 왜 마지막 요소가 아닌 마지막 요소 다음을 가리키는지에 대해서!
이에 대해서 chat gpt 에 물어봤는데 "Half-Open Range의 중요성이 반복자 범위는 "half-open" 범위로 알려져 있습니다. 즉, 시작은 포함되지만 종료는 포함되지 않습니다([begin, end)). 이러한 설계는 다음과 같은 이유로 안전성과 효율성을 제공합니다:범위 초과 방지:end()가 마지막 요소의 바로 다음을 가리키므로, 반복 과정에서 마지막 요소를 처리한 후 반복자를 한 번 더 증가시키면 end()를 가리키게 됩니다. 이 위치는 실제 데이터를 포함하지 않으며, 반복자가 데이터를 벗어난 상태가 되지 않습니다. 따라서 루프에서 it != vec.end() 조건을 검사할 때 정확히 루프가 종료되며, 이는 범위를 초과하여 데이터에 접근하는 일이 없도록 합니다.일관된 로직:모든 표준 알고리즘과 컨테이너 연산은 이 half-open 패턴을 기대합니다. 이로 인해 개발자는 특별한 경우를 고려하지 않고도 일관된 방식으로 코드를 작성할 수 있습니다. 이는 오류 가능성을 줄이고 코드의 가독성을 높여줍니다. "이렇게 답을 해줬습니다. end()가 마지막 요소를 직접 가리키는 경우 저는 오히려 범위 초과 방지에 더 도움이 된다고 생각하기에 이 설명이 이해가 잘 안 됩니다. 또 chat gpt에서"std::vector<int> vec = {1, 2, 3};auto it = vec.begin(); // it는 Index 0을 가리킵니다 (Element: 1) 여기에서 end()가 마지막 요소를 직접 가리키는 경우 (비표준, 가상 시나리오)이 경우를 가정하여, vec.end()가 Index 2, 즉 3을 가리킨다고 가정해 봅시다.반복 실행 과정:it는 1을 가리킵니다. it != vec.end()는 참입니다. 요소 1을 출력하고 ++it.it는 2를 가리킵니다. it != vec.end()는 참입니다. 요소 2를 출력하고 ++it.it는 3을 가리킵니다. it != vec.end()는 참입니다. 요소 3을 출력하고 ++it. 여기서 문제가 발생합니다. it를 한 번 더 증가시키면, it는 vec.end()를 넘어서 Index 3으로 이동하게 되고, 이 위치는 벡터의 범위를 벗어난 위치입니다. 이 시점에서 다음의 it != vec.end() 검사는 undefined behavior를 초래할 수 있습니다, 왜냐하면 it가 벡터의 유효 범위를 벗어났기 때문입니다. "이렇게 말을 했는데 이해가 잘 되지 않습니다. end()가 마지막 요소를 직접 가리키는 경우 it가 3을 가리킬 때 it != vec.end() 는 오히려 거짓이 되고, 3을 출력하기 전에 반복 실행을 멈추기 때문에 오히려 범위 밖으로 나갈 위험이 적다고 생각합니다. (물론 여기서는 3을 출력하지 않기 때문에 잘못된 것이지만). 그래서 chat gpt 가 마지막 요소 다음을 가리키는 게 더 안전하다고 한 이유를 잘 모르겠습니다. 오히려 end()는 마지막 요소 다음을 가리키는 반복자이므로 쓰레기 값을 가리키는 이상한 녀석이라는 생각이 듭니다.
- 미해결홍정모의 따라하며 배우는 C++
r-value reference와 std::move
안녕하세요! 항상 수고 많으십니다.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; } };
- 미해결홍정모의 따라하며 배우는 C++
class Derived : private Base일 경우질문
class Derived : private Base { public: Derived() { // private Base Base::m_public; // 손자 클래스에서 사용 불가 Base::m_protected; // 손자 클래스에서 사용 불가 // x Base::m_private; // 사용 불가 } };안녕하세요. 항상 고생 많으십니다.해당 코드에서class Derived : private Base가 되면. class Derived 내에서,Base::m_private는 당연히 접근이 불가능한 것은 맞는데 나머지Base::m_public; Base::m_protected; 에 대해서는 Derived내에서 접근이 가능한가요?손자 클래스에서는 접근이 불가능하다는 것을 말씀 해주셔서 이해 했는데, 자식 클래스에서는 접근 여부가 어떻게 될까요?
- 미해결홍정모의 따라하며 배우는 C++
익명객체 생성자호출
안녕하세요! 15:40경입니다. 간단한 궁금증이 있는데Monster mon1("Sanson", Position2D(0,1));교수님께서 위와같이 main함수 내에, 매개변수에 있는 것들로 Monster 클래스의 mon1의생성자를 호출하셨습니다.Monster클래스의 생성자는 아래와 같고,Monster(const std::string name_in, const Position2D & pos_in) : m_name(name_in), m_location(pos_in) {}스트링 문자열과, Position2D객체를 파라미터로 받는데요 Q) 이때 저 위에 있는Monster mon1("Sanson", Position2D(0,1));의 Position2D(0,1)는 익명객체이고 자신을 참조하는 레퍼런스const Position2D & pos_in에게 주소를 넘겨주고 생성자에 의해 private멤버 변수가 값복사에의한 초기화가 끝나는 즉시 Position2D(0,1)는 사라진다는 설명이 적절할까요? 감사합니다
- 미해결홍정모의 따라하며 배우는 C++
Assignment Operator의 delete[]
안녕하세요 9.11 13:50 부근입니다MyString& operator = (const MyString& source) { cout << "Assignment operator " << endl; if (this == &source) // prevent self-assignment return *this; delete[] m_data; m_length = source.m_length; if (source.m_data != nullptr) { m_data = new char[m_length]; for (int i = 0; i < m_length; ++i) m_data[i] = source.m_data[i]; } else m_data = nullptr; return *this; }해당 코드는 클래스 MyString의 대입연산자 입니다.가운데에 보시면 delete[] m_data;가 보이실텐데 교수님이 m_data가 이미 메모리를 가지고있었을 수도 있다고 하시는데 그 어떤 증례도 떠오르지 않습니다. int main함수 내에서{ MyString copy = hello; cout << (int*)copy.m_data << endl; cout << copy.getString() << endl; }다음과같이 copy가 그냥 여기서 처음 생기고 scope를 벗어나면 사라지는데이 이전에 copy의 m_data가 메모리를 가지고 있었다고 하는 것이 납득이 되지 않아서 간단한 설명 부탁드리고싶습니다. 감사합니다. ++수정)질문 작성 도중에 떠올랐는데 교수님이 말씀하신 케이스가이미 옛적에 copy를 만들어서 쓰고있었지만 그 본 것을 버리고 새로 다른 데에 쓰려고 새로 인스턴스를 대입해준다는 말씀이셨을까요? (--> 따라서 delete함으로써 전에 쓰던 주소를 계속 이어씀으로써 발생할 수 있는 UB를 방지??) (전체코드) #include <iostream> #include <cassert> using namespace std; class MyString { //private: public: char* m_data = nullptr; int m_length = 0; public: MyString(const char* source = "") { assert(source); m_length = std::strlen(source) + 1; m_data = new char[m_length]; for (int i = 0; i < m_length; ++i) m_data[i] = source[i]; m_data[m_length - 1] = '\0'; } MyString(const MyString& source) { cout << "Copy constructor " << endl; m_length = source.m_length; if (source.m_data != nullptr) { m_data = new char[m_length]; for (int i = 0; i < m_length; ++i) m_data[i] = source.m_data[i]; } else m_data = nullptr; } MyString& operator = (const MyString& source) { cout << "Assignment operator " << endl; if (this == &source) // prevent self-assignment return *this; delete[] m_data; m_length = source.m_length; if (source.m_data != nullptr) { m_data = new char[m_length]; for (int i = 0; i < m_length; ++i) m_data[i] = source.m_data[i]; } else m_data = nullptr; return *this; } ~MyString() { delete[] m_data; } char* getString() { return m_data; } int getLength() { return m_length; } }; int main() { MyString hello("Hello"); cout << (int*)hello.m_data << endl; cout << hello.getString() << endl; { MyString copy = hello; cout << (int*)copy.m_data << endl; cout << copy.getString() << endl; } cout << hello.getString() << endl; return 0; }
- 미해결홍정모의 따라하며 배우는 C++
증감연산자 오버로딩
안녕하세요 궁금한 것이 있어 여쭤봅니다 교수님께서 전위증가연산자 오버로딩 코드를 이렇게 짜셨습니다.class Digit { private: int m_digit; public: Digit(int digit = 0) : m_digit(digit) {} //prefix Digit& operator ++ () { ++m_digit; return *this; } friend ostream& operator << (ostream& out, const Digit& d) { out << d.m_digit; return out; } };아래는 main 함수 부분이고요int main() { Digit d(5); cout << ++d << endl; cout << d << endl; return 0; }여기 멤버함수로 구현이 돼있는데요Digit& operator ++ () { ++m_digit; return *this; }cout << ++d << endl; 에서 d를 만난다음 d가 ++연산자를 호출할텐데 ++m_digit;이렇게 d인스턴스의 m_digit을 바로 1증가 시켜준다면 그냥 여기서 끝나면 되는 것 아닌가요? 인스턴스d가 호출한 ++연산자에서 인스턴스d의 m_digit을 직접 1증가 시켜줬는데, 위에서 operator ++ 왼쪽에 적혀 있는 리턴형인 Digit&과 리턴하는 값인 return *this;가 대체 무엇을 하는지 그 작동과정이 전혀 감이 안 잡혀서 구글링도 하고 그랬는데 원하는 것을 얻지 못한 거 같습니다 ㅠㅠ자세한 설명 부탁드려도 될까요?감사합니다
- 해결됨홍정모의 따라하며 배우는 C++
클래스 멤버 함수에 대한 질문
안녕하세요!이번 강의에 대해 이해가 어려운 부분이 있어서 질문드립니다.1분 10초 쯤부터 교수님께서 이렇게 말씀하십니다.''setID와 getID는 함수인데, 그렇다면 이 함수들이 s1과 s2에 각각 따로 들어가 있을까?""그렇지 않다. 하나를 만들어놓고 중복해서 사용한다.""Simple 이라는 클래스의 모두가 공유해서 사용한다"그렇다면, s1과 s2에서 사용하는 setID와 getID의 주소는 같다는 것일까요?같다면, 어떻게 출력으로 확인해볼 수 있나요?질문이 많이 부족하지만 늘 많은 도움 주셔서 감사드립니다.- 학습 관련 질문을 남겨주세요. 상세히 작성하면 더 좋아요! - 먼저 유사한 질문이 있었는지 검색해보세요. - 서로 예의를 지키며 존중하는 문화를 만들어가요. - 잠깐! 인프런 서비스 운영 관련 문의는 1:1 문의하기를 이용해주세요.
- 미해결홍정모의 따라하며 배우는 C++
class 생성자 함수 오버로딩
안녕하세요. 8.5강 3:55 부근입니다. 교수님께서//아래는 Student Class의 생성자들입니다. Student(const string& name_in) //: m_id(0), m_name(name_in) : Student(0, name_in) {} Student(const int& id_in, const string& name_in) : m_id(id_in), m_name(name_in) {} ... 와 같이 Student 클래스에 생성자 두 개를 만드셨습니다. 이때, 아래와 같이 Student클래스에 대한 인스턴스가 각각 st1, st2이렇게 있는데요int main() { Student st1(0, "Jack Jack"); st1.print(); Student st2("Dash"); st2.print(); return 0; }st1는 Student st1(0, "Jack Jack"); 와 같이 (표현이 올바른지는 모르겠습니다 -->) 생성자 함수를 int와 string 두 개의 매개변수로 호출하는데, 이때, 이름이 같은 생성자 함수가 여러개 있음에도 함수 오버로딩을 통해 int와 string을 매개변수로 가지는 생성자 함수를 알아서 찾게 됨으로써Student(const int& id_in, const string& name_in) : m_id(id_in), m_name(name_in) {}의 생성자만 단독으로 호출되는 원리인가요? 감사합니다.
- 해결됨홍정모의 따라하며 배우는 C++
함수 reference 반환
안녕하세요 궁금증이 생겨 하나 여쭤봅니다.7.5강 8:42 부근입니다.int& getValue(int x) { int value = x * 2; return value; } int main() { int &value = getValue(5); cout << value << endl; cout << value << endl; ...return value; 에서 getValue함수의 반환값은 int 레퍼런스 형이니 main함수의 int &value = getValue(5); 부분에서호출자 getValue(5)는 int &~ = value;에서 ~의 부분에 해당하나요? 그렇다면 getValue에 있던 value 변수의 레퍼런스인데그렇게 되면 int &value = getValue(5);는 레퍼런스의 레퍼런스라 오류가 발생해야하는 것이 아닌가요? 감사합니다.
- 미해결홍정모의 따라하며 배우는 C++
short circuit evaluation
#include <iostream> using namespace std; int main() { //short circuit evaluation int x = 2; int y = 2; if (x == 1 && y++ == 2) { cout << "good" << endl; } cout << y << endl; return 0; }강의 18:05에서마지막에 y값이 2로 출력되는 이유가&&연산자는 왼쪽을 계산했을 때 false면 오른쪽을 계산하지않는다고 하셨습니다.if (x == 1 && y++ == 2)근데 이 문장에서 연산자 우선순위를생각해보면 y++ > == > &&니까 y++(후위증가연산자)먼저 되서 y는 이 문장이 끝나면 어쨌든 1이 증가되야하는것 아닌가요?그 후 그다음 연산자 우선순위인 ==, &&순으로 진행되어야 하지 않나요?제가 잘못이해한걸까요?
- 해결됨홍정모의 따라하며 배우는 C++
(과제스포)제가 과제를 똑바로 이해했는지 궁금합니다.
#include<chrono> #include<iostream> #include<mutex> #include<random> #include<thread> #include<utility> #include<vector> #include<atomic> #include<future> #include<numeric> #include<execution> using namespace std; mutex mtx; void dotProductDQThread(const vector<int>& v0, const vector<int>& v1, const unsigned i_start, const unsigned i_end, unsigned long long& sum) { int sum_tmp = 0; //local sum for (unsigned i = i_start; i < i_end; ++i) { sum_tmp += v0[i] * v1[i]; } sum += sum_tmp; } void dotProductProm(const vector<int>& v0, const vector<int>& v1, const unsigned i_start, const unsigned i_end, promise<unsigned long long>&& sum) { int sum_tmp = 0; //local sum for (unsigned i = i_start; i < i_end; ++i) { sum_tmp += v0[i] * v1[i]; } sum.set_value(sum_tmp); } int main() { /*v0 = { 1,2,3 }; v1 = { 4,5,6 }; v0_dot = 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); random_device seed; mt19937 engine(seed()); uniform_int_distribution<> uniformDist(1, 10); //v0와 v1에 값 무작위로 넣어줌 for (long long i = 0; i < n_data; ++i) { v0.push_back(uniformDist(engine)); v1.push_back(uniformDist(engine)); //cout << v0[i] << "\t" << v1[i] << endl; } 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);//0ull = unsigned longlong 0 const chrono::duration<double> dur = chrono::steady_clock::now() - sta; cout << dur.count() << endl; cout << sum << endl; cout << endl; } //TODO: use divde and conquer strategy for std::thread cout << "TODO: use divde and conquer strategy for std::thread" << 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; for (unsigned t = 0; t < n_threads; ++t) threads[t] = std::thread(dotProductDQThread, 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; } //TODO: use promise cout << "TODO: use promise" << endl; { const auto sta = chrono::steady_clock::now(); //std::promise<unsigned long long> sum; auto sum = 0ull; vector<thread> threads; vector<future<unsigned long long>> futures; vector<promise<unsigned long long>> proms; threads.resize(n_threads); futures.resize(n_threads); proms.resize(n_threads); const unsigned n_per_thread = n_data / n_threads; for (unsigned t = 0; t < n_threads; ++t) { futures[t] = proms[t].get_future(); threads[t] = std::thread(dotProductProm, 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) { threads[t].join(); sum += futures[t].get(); } const chrono::duration<double> dur = chrono::steady_clock::now() - sta; cout << dur.count() << endl; cout << sum << endl; cout << endl; } }결과는 제대로 나오지만, 제가 과제를 똑바로 이해했는지 궁금해서 여쭤봅니다.과제1: use divde and conquer strategy for std::thread쓰레드에 sum에 local sum값을 넣어 race condition 해결과제2: prom 사용해보기sum 변수 선언 및 thread, promise, future 모두 쓰레드 크기 만큼의 vector로 만들어줬습니다. 병렬 처리 후 future값을 sum에 더해줬습니다.※추가 궁금증promise 과제 중, std::ref와 std::move 둘 다 해보았습니다. 두 경우 모두 정상 작동하였는데, 어떤 방법을 가장 추천하시나요?
- 미해결홍정모의 따라하며 배우는 C++
헤더파일 포함 컴파일 방법
- 학습 관련 질문을 남겨주세요. 상세히 작성하면 더 좋아헤더 파일을 포함한 파일에 대해 컴파일하는 방법이 궁금합니다.다른 분 답변에서는 makefile을 사용하라고 다른 분께서 말씀하시던데 이해가 되지 않아 남겨봅니다.
- 미해결홍정모의 따라하며 배우는 C++
\n과 endl의 차이
강의 19:25를 보면 '\n'은 단순 줄 바꿈이고 'endl'의 경우 줄을 바꿈과 동시에 버퍼에 있는 모든 것을 출력한다고 하셨습니다. #include <iostream> using namespace std; int main() { char c1; cin >> c1; cout << c1 << endl; return 0; }제가 간단하게 예제를 만들었습니다.실행 후에 c1에 입력을 단순히 하나의 문자가 아니라 12345처럼 문자열을 넣으면 c1에는 1이 담기고 2345는 버퍼에 저장된다고 생각했습니다.endl;이 버퍼에 있는 모든 것을 출력하니까 12345 모두 출력될 줄 알았는데 1만 출력되었습니다.제가 잘못 이해한 것일까요? 감사합니다.
- 미해결홍정모의 따라하며 배우는 C++
#pragma once vs. #ifndef
header guard로 #pragma once를 쓰는 방법과 #ifndef 쓰는 방법 두개를 설명해주셨는데, 두 개의 차이점이 있을까요?구글링해보면 #pragma once가 처리속도가 빠르지만, 지원되지 않는 compiler가 있는 것 같고 (현재는 대부분의 compiler는 지원되지만), #ifndef 는 모든 compiler에서 지원되지만 처리속도가 #pragma once에 비해서 느리다 라는 것 같은데, 맞는 내용인지 모르겠네요.
- 미해결홍정모의 따라하며 배우는 C++
쓰레드 이동 생성자 질문
#include<iostream> #include<future> #include<thread> using namespace std; int main() { { std::promise<int> prom;//future를 받아주는 존재가 필요해서 promise 거침 auto fut = prom.get_future(); auto t = std::thread([](std::promise<int>&& prom) { this_thread::sleep_for(chrono::milliseconds(1000)); prom.set_value(1 + 2); }, std::move(prom));//prom소유권을 넘겨받음 cout << "before get" << endl; cout << fut.get() << endl;//prom이 setvalue되어 값을 받아오도록 fut은 계속 기다림 cout << "after get" << endl; t.join();//thread끝나는 걸 기다려줌 } }위 코드를 전 아래처럼 이해했습니다futre가 promise의 future를 공유 받음 쓰레드 생성되며 promise의 소유권을 받음(여전히 future와 공유 관계)fut가 prom의 setvalue까지 기다림prom의 setvalue후 fut 출력됨쓰레드 join쓰레드에 std::move의 존재 이유가 궁금해서 알아보니, 쓰레드의 이동생성자였습니다. 그래서 prom의 소유권이 쓰레드로 가는건가 궁금합니다. 쓰레드 생성 후 prom.set_value(1)을 해보니 에러가 뜨기도 했습니다.
- 미해결홍정모의 따라하며 배우는 C++
코드 실행속도가 너무 느립니다.
강의를 보고 따라한 아래 코드의 실행속도가 강사님에 비해 너무나 느립니다. 실행환경의 문제인가요??#include<iostream> #include<thread> #include<atomic>//나눌 수 없다는 뜻. 쓰레드에서 연산이 한번에 이루어지도록 함 #include<mutex> #include<chrono> using namespace std; mutex mtx; int main() { //atomic<int> shared_memory(0); int shared_memory(0); auto count_func = [&]() { for (int i = 0; i < 1000; ++i) { //cout << shared_memory << endl; this_thread::sleep_for(chrono::milliseconds(1)); //doSomething; //mtx.lock(); //std::lock_guard lock(mtx);//unlock필요없음 std::scoped_lock lock(mtx); shared_memory++; //shared_memory.fetch_add(1); //mtx.unlock(); //shared memory의 값을 더할 떄의 과정 //1.shared memory값을 cpu로 가져옴 //2.1더함 //3.sharedmemory에 결과 저장 //값을 읽어들었을 때, 값이 바뀌면 더하기가 씹혀버림 => 잘못된 결과 //해결법 //1. atomic 사용 //2. fetchadd //3. mutex lock } }; thread t1 = thread(count_func); thread t2 = thread(count_func); t1.join(); t2.join(); std::cout << "After" << endl; std:: cout << shared_memory << endl; return 0; }
- 미해결홍정모의 따라하며 배우는 C++
맥 "clang: error: linker command failed with exit code 1 " 에러
안녕하세요 맥 사용자 입니다. 답변으로 아래와 같이 추가 질문 드립니다.
- 미해결홍정모의 따라하며 배우는 C++
맥 "clang: error: linker command failed with exit code 1 " 에러
- 학습 관련 질문을 남겨주세요. 상세히 작성하면 더 좋아요! 안녕하세요 맥 사용자입니다.본 강의 챕터 관련하여 궁금한 점이 있어 글을 남깁니다.커뮤니티에서 "lahat"님의 문제와 답변을 참고 삼아 clang+ add.cpp main_chapter1_11.cpp로 링킹 하였으나, main_chapter1_11.cpp파일이 "clang: error: linker command failed with exit code 1 "와 같은 오류 메세지를 띄고 있고 a.out 프로그램은 실행은 정상적으로 실행이 됩니다. 여기서 궁금한 점은 링킹을 정상적으로 성공 후에도 main.cpp에서는 위와 같은 오류 메세지를 띄고 있는 지 궁금합니다. 바쁘신 와중에 긴 글을 읽어주셔서 감사합니다.