Code Monkey home page Code Monkey logo

cpp-study's People

Contributors

hsg2311 avatar woon-2 avatar

Watchers

 avatar

cpp-study's Issues

En004. 코드 중복을 줄이는 것이 좋습니다.

Issue Description

code에서 공통된 성격을 가진 dataoperation들이 반복된다면,
function이나 classabstract하는 것이 좋습니다.

과제에서 요구하는 건 최소한의 요구치입니다.
좋은 code를 위해 몇 가지 function이나 class를 더 추가하셔도 괜찮습니다.


또한, 약간의 성능을 희생해서
code duplication을 제거하는 편이 좋을 수 있습니다.

파레토 법칙이 프로그래밍에 응용되어

런타임의 80%를 잡아먹는 코드는 전체 코드의 20%밖에 되지 않는다.

라는 관용 표현이 많이 쓰이는데요.
자잘한 성능에 신경쓰는 것보다 런타임 성능에 실제로 영향을 끼치는
20%의 code를 찾아내는 것이 중요하다는 의미입니다.

Issue Context

Jongjin's-studyroom
b54f2ef - CS-1 CS-391 CS-396 레퍼런스 반환 과제 Commit에 대한 Issue입니다.

TestScore& min(TestScore& lhs, TestScore& rhs)
{
int lhs_sum = lhs.math + lhs.english + lhs.physics + lhs.chemicals;
int rhs_sum = rhs.math + rhs.english + rhs.physics + rhs.chemicals;
if (lhs_sum < rhs_sum)
return lhs;
else
return rhs;
}

TestScore& max(TestScore& lhs, TestScore& rhs)
{
int lhs_sum = lhs.math + lhs.english + lhs.physics + lhs.chemicals;
int rhs_sum = rhs.math + rhs.english + rhs.physics + rhs.chemicals;
if (lhs_sum > rhs_sum)
return lhs;
else
return rhs;
}

TestScore& median_of_three(TestScore& one, TestScore& two, TestScore& three)
{
int one_sum = one.math + one.english + one.physics + one.chemicals;
int two_sum = two.math + two.english + two.physics + two.chemicals;
int three_sum = three.math + three.english + three.physics + three.chemicals;
if (one_sum > two_sum)
{
if (one_sum > three_sum)
{
if (two_sum > three_sum)
return two;
else
return three;
}
else
return one;
}
else // one_sum < two_sum (같은 경우는 어찌 해야되지..?)
{
if (one_sum > three_sum)
{
return one;
}
else
{
if (two_sum > three_sum)
return three;
else
return two;
}
}
}

Enhancement

int sum(TestScore& ts)
{
    return ts.math + ts.english + ts.physics + ts.chemicals;
}
TestScore& min(TestScore& lhs, TestScore& rhs)
{
    if (sum(lhs) < sum(rhs))
        return lhs;
    else
        return rhs;
}
TestScore& max(TestScore& lhs, TestScore& rhs)
{
    if (&min(lhs, rhs) == &lhs)    // 파레토 법칙을 참고해,
        return rhs;               // 몇 개의 연산을 늘리는 대신
    else                          // 구현상의 코드 중복을 제거했습니다.
        return lhs;               // 추상화 수준이 가장 비슷한 함수를 이용하도록 합니다.
}
TestScore& median_of_three(TestScore& one, TestScore& two, TestScore& three)
{
    int one_sum = sum(one);
    int two_sum = sum(two);
    int three_sum = sum(three);

    // 이하 기존과 동일
    
    // ...

    // 여기도 파레토 법칙을 참고하면
    // return min(max(one, two), max(two, three)); 의 한 줄로 끝낼 수도 있습니다.
}

En005. 함수의 선언에서 함수의 동작을 유추할 수 있어야 합니다.

Issue Description

제가 과제에서 function parameter들을 n, m, k, l 따위로 표현하긴 했으나,
여러분이 실제로 작성한 parameter의 이름은 설명적이어야 합니다.

일반적으로 variable이 쓰이는 범위가 클수록
더 길고 정확하게 그 variable의 역할을 설명하는 이름이 필요합니다. (Code Complete 2, Steve McConnell, 11.1)

function parameter는 보통 function 전체에 걸쳐서 쓰입니다.
code에서의 물리적 access 말고도
사용자가 해당 function이 무슨 일을 하는지 유추할 때에
우리의 눈에 의해서 심리적으로도 access되죠.

그것을 감안해 n, m, k, l 따위의 이름은 피하도록 합시다.
이 논지의 내용을 해당 과제에 추가토록 하겠습니다.

Issue Context

Jongjin's-studyroom
fde7960 - CS-1 CS-119 CS-222 replace 함수의 parameter를 수정 Commit에 대한 Issue,

const char& at(const size_t n) const;
const char& front() const;
const char* c_str() const;
const char* data() const;
bool empty() const;
int size() const;
int length() const;
void reserve(const size_t n);
size_t capacity();
void shrink_to_fit();
void resize(const size_t n);
void clear();
void insert(const size_t n, const char* other);
void erase(const size_t n, const size_t m);
void push_back(const char c);
void pop_back();
void append(const char c);
int compare(const char* other) const;
void replace(size_t n, size_t m, size_t k, size_t l, const char* s);
const my_string& substr(const size_t n, const size_t m);
int find(const char* str) const;

Sanghoon's-studyroom
2898e9f - CS-1 CS-187 Commit에 대한 Issue입니다.

char& at( size_t );
char& front( );
char& back( );
const char* c_str( );
const char* data( );
bool empty( );
size_t size( );
size_t length( );
void reserve( size_t );
int capacity( );
void shrink_to_fit( );
void resize( size_t );
void clear( );
void insert( size_t, const char* );
void erase( size_t, size_t );
void push_back( char );
void pop_back( );
void append( char );
int compare( const char* );
void replace( const char*, const char* );
const char* substr( size_t, size_t );
int find( const char* );

Enhancement

  • n, m, k, l 등의 parameter 이름을 더 설명적이도록 수정합니다.
  • function declarationparameter의 이름을 적지 않았다면, 적도록 합니다.

Reference

Steve McConnell, 『Code Complete 2』, 서우석 옮김, (위키북스, 2020)
Robert C. Martin, 『Clean Code』, 박재호, 이해영 옮김, (인사이트, 2013)

Bu004. mystring.inl에 정의된 operator>> 오류

오류 목록

image

오류가 뜬 부분 Link

operator>>(std::basic_istream<CharT, Traits>& is,
my_string<CharT>& str)
{
static constexpr std::size_t str_max_size = 1'000'000'000;
using istream_type = std::basic_istream<CharT, Traits>;
using string_type = my_string<CharT>;
using ios_base = typename istream_type::ios_base;
using int_type = typename istream_type::int_type;
using ctype = std::ctype<CharT>;
using ctype_base = typename ctype::ctype_base;
std::size_t extracted = 0;
typename ios_base::iostate err = ios_base::goodbit;
typename istream_type::sentry cerb(is, false);
if (cerb)
{
try
{
// Avoid reallocation for common case.
str.clear();
CharT buf[128];
std::size_t len = 0;
const std::streamsize width = is.width();
const std::size_t n = width > 0 ? width : str_max_size;
const ctype& ct = std::use_facet<ctype>(is.getloc());
const int_type eof = Traits::eof();
int_type c = is.rdbuf()->sgetc();
while (extracted < n
&& !Traits::eq_int_type(c, eof)
&& !ct.is(ctype_base::space,
Traits::to_char_type(c)))
{
if (len == sizeof(buf) / sizeof(CharT))
{
str.append(buf, sizeof(buf) / sizeof(CharT));
len = 0;
}
buf[len++] = Traits::to_char_type(c);
++extracted;
c = is.rdbuf()->snextc();
}
str.append(buf, len);
if (extracted < n && Traits::eq_int_type(c, eof))
err |= ios_base::eofbit;
is.width(0);
}
catch(...)
{
is.setstate(ios_base::badbit);
}
}
if (!extracted)
err |= ios_base::failbit;
if (err)
is.setstate(err);
return is;
}

추가 스크린샷

  • 오류(활성) E0658 템플릿 정의의 닫는 중괄호를 찾을 수 없습니다.

image

  • str_max_size가 정의되어 있지만 정의되지 않았다고 뜸
  • 클래스 템플릿 인수를 추론할수 없음

image

이하 생략

Do004. 멤버 함수 선언 과제 수정

Issue Description

my_stringreplace 함수의 설명이 바뀌었습니다.
다른 구현이 필요해지므로, 멤버 함수 선언 과제를 위한 코드를 작성하셨다면 참고하여 수정해주시기 바랍니다.

Issue Context

assignments
94c17d9 - refactoring Commit에 대한 Issue입니다.
#45 의 '22.12.04. 스크럼에서 말씀드렸던 내용입니다.

두 분 다 확인하셨다고 댓글 달아주시면 Issue를 닫겠습니다.

En001 코드 리팩터링 - assert와 if를 동시에 쓰지 않기를 권장합니다.

Jongjin's-studyroom
6c5f5bf - 더블 링크드 리스트 클론 코딩 Commit에 대한 Issue입니다.

LinkedList.h

...

150	T front()const
151	{
152		if (empty())
153			assert(false);
154
155		return m_pBegin->m_pNext->m_Data;
156	}
157
158	T back()const
159	{
160		if (empty())
161			assert(false);
162
163		return m_pEnd->m_pPrev->m_Data;
164	}

...
  • assert는 인자가 false이면 프로그램을 중단합니다.

    • assert는 단정하다라는 뜻으로, 인자인 statement가 항상 참임을 단정합니다.
      단정문이라고 부르죠.
  • 비슷한 예로 expect도 있습니다.

    • expect는 인자인 statement가 참일 것이 기대됨을 나타냅니다.
  • assert, expect와 같은 함수들은 오류 검출 코드 작성 시 번거로운 if문 생성을 피하도록 해줍니다.
    다음과 같이 개선할 수 있겠죠.

LinkedList.h

	T front()const
	{
		assert(!empty());

		return m_pBegin->m_pNext->m_Data;
	}

	T back()const
	{
		assert(!empty());

		return m_pEnd->m_pPrev->m_Data;
	}

작은 변화지만 더 깔끔한 코드가 되었습니다.

En003 - 조건부 컴파일문과 포함문의 순서 변경

Issue Description

conditional compilation문이 source 전체를 감싸는 큰 틀이어야 합니다.
conditional compilation문 안에 include문이 감싸져 있지 않다면,
해당 sourceinclude될 때마다 모든 include문들이 preprocessor에 의해 중복 실행될 것입니다.

Issue Context

Jongjin's-studyroom
fe912a8 - 2.write preprocessor directives Commit에 대한 Issue입니다.

#include <cstddef>
#include <limits>
#ifndef mat
#define mat
#endif

#include <type_traits>
#ifndef my_shared_ptr
#define my_shared_ptr
#endif

#include <cstring>
#ifndef my_string
#define my_string
#endif

#include <type_traits>
#ifndef my_unique_ptr
#define my_unique_ptr
#endif

#pragma once
#include <cstddef>
#include <limits>
#ifndef vec
#define vec
#endif

Enhancement

#ifndef vec
#define vec

#include <cstddef>
#include <limits>

#endif

양상은 같으므로, 한 source에 대해서만 수정 내용을 작성했습니다.

#pragma once 또한 필요하지 않습니다.
#pragma once는 한 번만 compile하라는 preprocessor directive인데, 표준이 아닙니다.
conditional compilation이 정확히 같은 역할을 하므로, 둘을 중복해서 사용하지 않는 것이 좋습니다.

Detail

Go001. Issue 사용법

Issue 사용법

Github Issue의 전반적인 사용법을 알리기 위한 글입니다.

어떨 때 사용하는가

  • Issue는 프로젝트 내의 코드에 대해 특정한 문제 사항을 보고/확인을 위한 용도입니다.

  • 버그나 코드 중복, 오탈자, 문서화 오류 등을 보고합니다.

    • 어떤 종류의 Issue가 있는지는 ★라벨★을 참고하세요.

사용 양식

뉴이슈, 오픈클로즈

  • Open 상태인 Issue는 아직 해결되지 않은 Issue라는 뜻이고
    Closed 상태인 Issue는 해결된 이슈라는 뜻입니다.
  • New issue를 통해 Issue를 생성하면 생성된 Issue는 바로 Open 상태가 됩니다.
  • Open 상태의 Issue를 발견하면, 바로바로 확인할 수 있도록 합니다.

클로즈, 코멘트, 어싸인, 라벨

  • 방금 전의 창에서 개별 Issue를 클릭하면 나오는 Issue 창입니다.

  • 본문에 적힌 Issue 내용을 보고, 댓글을 통해 소통합니다.

  • IssueAssignee(담당자)를 설정할 수 있습니다.

    • Assignee들은 자신이 Assignee로 설정된 Issue들을 빠르게 해결할 책임을 갖습니다.
    • 알맞은 Assignee를 설정합시다.
  • Issue가 해결되었다면, Close 합니다.

    • 직접 Close 버튼을 눌러도 되고,
    • CommitClose 명령어를 추가해도 됩니다.

어싸인

  • 담당자를 설정하는 창입니다.

라벨

  • 라벨을 설정하는 창입니다.

En002 - fstream으로부터 데이터 입력 & 컨테이너에 원소를 입력하는 효율적인 방법

Issue Description

불필요한 동작이 코드 상에 존재합니다.

  • fstream만으로 데이터를 입력 받을 수 있음에도, stringstreamarray를 거쳐서 입력받고 있습니다.
  • 컨테이너에 원소를 입력하는 것만이 필수적인 동작입니다.
    그 외의 복사 동작은 필요하지 않습니다.
  • fstreamRAII class이므로 close 메서드를 호출하지 않아도 destructor에서 기존에 획득한 파일 자원을 해제합니다.

Issue Context

Jongjin's-studyroom
79d9bfb2ae4c678008af32d3d4e4a7b7e3c6252a - Update main.cpp Commit에 대한 Issue입니다.

template<>
void readData(CLinkedList<Champion>& _Linkedlist)
{
ifstream fin("data.txt");
char line[100];
while (fin.getline(line, sizeof(line)))
{
Champion c;
istringstream iss(line);
iss >> c.name >> c.hp >> c.mp >> c.attack >> c.defense;
_Linkedlist.push_back(c);
}
fin.close();
}

Enhancement

Solution 1

template<>
void readData(CLinkedList<Champion>& _Linkedlist)
{
	ifstream fin("data.txt");

	while (fin.good())
	{
		Champion c;
		fin >> c.name >> c.hp >> c.mp >> c.attack >> c.defense;	// fstream으로부터 데이터 입력

		_Linkedlist.push_back(move(c));	// std::move 활용
	}

	// fin.close() - fstream은 RAII 클래스, 소멸자를 믿자.
}

Solution 2

template<>
void readData(CLinkedList<Champion>& _Linkedlist)
{
	ifstream fin("data.txt");

	while (fin.good())
	{
		_Linkedlist.push_back({});		// default object 추가 후 수정, emplace_back 메서드가 없으므로 push_back을 사용함.
		auto& [name, hp, mp, attack, defense] = _Linkedlist.back();	// C++17, structured binding

		fin >> name >> hp >> mp >> attack >> defense;
	}

	// fin.close() - fstream은 RAII 클래스, 소멸자를 믿자.
}

Detail

fstreamstringstreamios로부터 상속된 여러 종류의 stream들은 buffer를 갖습니다.
stringbasic_string<char>typedef이듯이,
iosbasic_ios<char>typedef입니다.
iosbufferchar을 저장하는 배열이죠.

istreamoperator>>overload되어 있습니다.
istreamoperator>>buffer의 데이터를 delimiter(구분자)를 기준으로 끊어서 추출합니다.
기본적으로 delimiter는, 공백/띄어쓰기입니다.

buffer는 문자열이고, istream에서 buffer의 내용을 한 단어씩 추출할 수 있다는 것을 아셨을 겁니다.
fstreamistream을 상속해 operator>>가 있으므로, 데이터 입력을 위해 추가적인 동작이 필요 없습니다.
한 개의 istream만으로 모든 입력을 할 수 있습니다.


데이터의 입력은 수정입니다.
입력 받을 메모리를 먼저 확보해야 하므로 데이터의 입력을 constructor call로 구현할 수 없다는 문제가 발생합니다.
따라서 어느 정도 불필요한 복사 동작이 발생하는 건 불가피하죠.

다음의 방법을 통해 그나마 최적화할 수 있습니다.

  • std::move를 통해 입력 받은 객체의 소유권 이전하기

    • 함수 인자인 객체에 std::move를 씌워주면 인자의 data typer-value reference가 되어
      이동 생성을 하는 버전의 push_back이 호출됩니다. (컨테이너에서 구현을 했다면 말이죠.)

    • built-in data type들은 복사와 이동의 비용 차이가 없습니다.

    • 다만, Championstd::string을 멤버로 갖고 있다면, std::stringmove constructor가 호출되어
      연산이 더 가벼워질 겁니다.
      (Championmove constructor를 직접 작성하지 않아도 됩니다.
      move constructorcompiler가 자동으로 만들어주는 special member function 중 하나로,
      멤버 변수들의 move constructorcall합니다.)

      • 왜 연산이 가벼워지는지 자세한 설명은 따로 질문해주시면 답하겠습니다.
        기본 골자는, deep copy가 아니라 shallow copy를 하기 때문입니다.
  • emplace_back, emplace 등의 메서드를 통해 default object를 컨테이너에 추가한 후 수정하기

    • 데이터 입력 후 객체의 용량이 커지는 경우가 있습니다.
      std::string의 경우가 그렇죠.
      용량이 커진 객체를 컨테이너로 복사하는 것보다
      컨테이너에 먼저 객체를 추가한 후 그 객체를 수정하는 게 훨씬 효율적입니다.

    • push_back은 객체를 인자로 받아 컨테이너 내에서 복사 생성 또는 이동 생성하는 동작입니다.
      push_back call 전에 constructor call이 일어나고,
      컨테이너에서 copy constructor call 또는 move constructor call이 일어납니다.

    • emplace_back은 객체 생성에 필요한 데이터를 인자로 받아 컨테이너 내에서 생성하는 동작입니다.
      컨테이너 내에서 constructor call 한 번만이 일어납니다.

In001. 동적 할당 과제의 변경 내용을 코드에 반영해야 합니다.

Issue Description

ea6adf4 - refactoring CS-1 CS-114 CS-382 CS-134 Commit으로
9.allocate&deallocate memory dynamically 과제의 void* operator new(std::size_t)를 구현하는 내용이 바뀌었습니다.
(#45 의 2022.12.05. 스크럼 참조)

이에 따른 최신화가 필요합니다.

Issue Context

Jongjin's-studyroom
fbd9a08 - CS-1 CS-122 CS-386 TODO - malloc/free와 new/delete의 차이 작성 Commit에 대한 Issue입니다.

void* operator new(std::size_t sz)
{
std::cout << __FUNCTION__ << " entry\n";
if (sz == 0)
++sz; // avoid std::malloc(0) which may return nullptr on success
if (void* ptr = std::malloc(sz)) // C++17, if statement with initializer
{
std::cout << __FUNCTION__ << " exit\n";
return ptr;
}
throw std::bad_alloc{}; // required by [new.delete.single]/3
}

Bu001 - 중복된 typename을 사용하지 않아야 합니다.

Jongjin's-studyroom
6c5f5bf - 더블 링크드 리스트 클론 코딩 Commit에 대한 Issue입니다.

LinkedList.h

5 template <typename T>
6 class CListNode
7 {
8 	template <typename T>
9 	friend class CLinkedList;

...

T라는 typename이 중복되어 Compile이 불가합니다.
Visual Studio에선 보통 두 개 이상의 typename을 사용할 때 Tx, Ty와 같이 구분합니다.

2022-11-02 추가

[Stack Overflow] Class template with template class friend, what's really going on here?

위 링크에 같은 문제 상황에 대한 토론이 있습니다.

Do002 - 멤버 함수 선언 과제 수정

Issue Description

my_unique_ptrrelease 함수의 설명이 바뀌었습니다.
다른 구현이 필요해지므로, 멤버 함수 선언 과제를 위한 코드를 작성하셨다면 참고하여 수정해주시기 바랍니다.

Issue Context

assignments
f0d707d - fixed description of my_unique_ptr<T>::release() Commit에 대한 Issue입니다.

두 분 다 확인하셨다고 댓글 달아주시면 Issue를 닫겠습니다.

Bu005. test case 작성 중 예기치 못한 오류?

image

test10번 작성후 11번 작성하고 컴파일했는데 오류가 뜨네요.

10번은 정상적으로 돌아갔는데 그 이후에 오류가 생기더니 test1번 조차 안돌아가는 상태입니다.

Bu002. 템플릿 변수를 함수의 매개변수로 전달

CLinkedList<Champion> listChampion;
readData(listChampion);

template<typename _T>
void readData(CLinkedList<_T>& _Linkedlist)
{
Champion c = { "Lenoa" ,120, 100, 20, 3 };
_Linkedlist.push_back(c);
}

CLinkedList에는 원소를 뒤에 추가할수있는 push_back 함수가 있습니다.

파일에서 데이터를 모두 읽어 push_back하는 기능을 가진 함수를 만들려고 합니다.

함수의 매개변수를 CLinkedList<_T>& _Linkedlist으로 정의하였으나
main에서와는 달리 push_back 함수를 호출할 수 없었습니다.

어떻게 해야할까요.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.