콘월 이층집

전체 글

Google C++ Style Guide 정리하기 - Functions

반응형

Functions

Inputs and Outputs

함수의 출력은 자연스럽게 반환 값을 통하며, 때로는 매개 변수를 통해 제공한다.

매개변수 보다 반환 값을 사용하는 것을 선호한다.

  • 가독성을 향상시키고 종종 동일하거나 더 나은 성능을 제공
  • Null 이 될 수 없는 한 원시 포인터를 반환하지 않음

std::optional을 사용하여 값에 의한 선택적 입력을 나타내고, 비 선택적일 때 const 포인터를 사용한다.

Write Short Functions

가능한 짧고 단순하게 작성하여 작고 집중된 기능으로 구현한다.

  • 단, 함수를 구성하는 코드 길이에 대한 제한은 없다.
  • 40 줄을 초과하는 경우에는 프로그램의 구조를 해치지 않고 분해할 수 있는지 고민해보길 권유
  • 함수를 짧고 단순하게 유지하면 다른 사람들이 코드를 더 쉽게 읽고 수정할 수 있음
  • 기능 별로 나눠두면 테스트 하기에 용이함

Function Overloading

함수 오버로딩을 사용할 때는 호출하는 코드만 보고도 어떤 함수가 실행 될지 쉽게 알 수 있어야 한다.

  • 예시 1. 함수의 의미가 다른데 적절하지 않게 오버로딩을 사용한 경우
void Process(int value);
void Process(double value);
void Process(bool flag);
void Process(const std::string& str);
void Process(const std::vector<int>& data);

 

const 또는 & (래퍼런스)로 인한 오버로딩은 유용하게 활용이 가능하다.

 

class Widget {
 public:
  void PrintInfo() &;   // 인스턴스에서 호출 가능
  void PrintInfo() &&;  // 임시 객체에서만 호출 가능
};

Widget w;
w.PrintInfo();  // ✅ PrintInfo() & 호출됨
Widget().PrintInfo();  // ✅ PrintInfo() && 호출됨

Default Arguments

가독성을 높이는 데 유용하지만, 오버로딩과 비교하여 신중하게 선택해야한다.

가상(virtual) 함수에서는 사용하지 않는다.

class Base {
public:
    virtual void Speak(std::string msg = "Hello from Base!") {
        std::cout << msg << std::endl;
    }
};

class Derived : public Base {
public:
    void Speak(std::string msg = "Hello from Derived!") override {
        std::cout << msg << std::endl;
    }
};

int main() {
    Derived d;
    Base* b = &d;
    
    b->Speak();  // "Hello from Base!" 출력 (❌ 예상과 다름)
}

Trailing Return Type Syntax

람다(lambda) 함수와 같이 특정 상황에서만 필요한 선언 스타일로, 일반적으로는 선행 반환 타입(Leading Return Type)을 사용한다.

  • 선행 반환 타입과 후행 반환 타입(Trailing Return Type)
int foo(int x); // 선행 반환 타입
auto foo(int x) -> int; // 후행 반환 타입, C++ 11 이상
  • 람다에서 반환 타입을 명시할 때는 반드시 후행 타입을 사용
  • 생략하면 컴파일러가 자동으로 반환 타입을 추론
auto lambda = [](int x, int y) -> int {
    return x + y;
};
  • 템플릿에서 반환 타입이 매개변수에 따라 달라질 때 사용
template <typename T, typename U>
auto add(T t, U u) -> decltype(t + u);
반응형

Google C++ Style Guide 정리하기 - Classes

반응형

Classes

Doing Work in Constructors

생성자에서 가상 메서드를 호출하지 않도록 하고, 오류 신호를 보낼 수 없는 경우 초기화가 실패할 수 있을 것을 방지해야 한다.

Implicit Conversions

암시적 변환을 정의하지말고, explicit 키워드를 사용한다.

class Foo {
  explicit Foo(int x, double y);
  ...
};

void Func(Foo f);
Func({42, 3.14});  // Error
Func(Foo(42, 3.14)); // OK

Copyable and Movable Types

클래스의 public API는 클래스가 복사가 가능한지, 이동만 가능한지, 복사하거나 이동할 수 없는지 여부를 분명하게 해야 한다.

  1. 복사 가능(Copyable)한 객체
  • 같은 타입의 다른 객체를 사용해서 생성 가능 (복사 생성자)
  • 같은 타입의 다른 객체를 사용해서 대입 가능 (복사 대입 생성자)
  • 원본 객체의 값은 변하지 않음 (즉, 원본과 동일한 객체를 가진 새로운 객체가 생성됨)
  • 예시 1. 복사 가능한 객체
int a = 10;
int b = a;  // ✅ 복사 가능

std::string s1 = "hello";
std::string s2 = s1;  // ✅ 복사 가능 (s2도 "hello"를 가짐)
  • 예시 2. 사용자 정의 복사 가능 클래스
class Copyable {
 public:
  Copyable(const Copyable& other) = default;  // 복사 생성자
  Copyable& operator=(const Copyable& other) = default;  // 복사 대입 연산자
};

 

 

2. 이동 가능(Movable)한 객체

  • 임시 객체(temporary object)로부터 데이터를 가져올 수 있는 객체
  • 이동이 가능한 경우, 복사보다 빠르게 데이터를 전송할 수 있음
  • 이동 이후 원본 객체의 상태는 “비워진(empty)” 상태 (이전 데이터를 다른 객체가 가져갔기 때문)
  • 예시 1. 이동 가능한 객체 (std::unique_ptr)
std::unique_ptr<int> p1 = std::make_unique<int>(10);
std::unique_ptr<int> p2 = std::move(p1);  // ✅ 이동 가능 (p1은 더 이상 10을 소유하지 않음)
  • 예시 2. 사용자 정의 이동 가능 클래스
 public:
  MoveOnly(MoveOnly&& other) = default;  // 이동 생성자
  MoveOnly& operator=(MoveOnly&& other) = default;  // 이동 대입 연산자

  MoveOnly(const MoveOnly&) = delete;  // 복사는 금지
  MoveOnly& operator=(const MoveOnly&) = delete;  // 복사는 금지
};

 

3. 객체 슬라이싱 문제

  • 기반 클래스(base class)를 복사할 때, 파생 클래스(derived class)의 정보가 손실되는 현상
  • 예시 1.
class Base {
 public:
  virtual void Print() { std::cout << "Base\n"; }
};

class Derived : public Base {
 public:
  void Print() override { std::cout << "Derived\n"; }
};

void Func(Base b) {  // ❌ 복사 생성자로 인해 slicing 발생
    b.Print();  // 항상 Base::Print() 호출됨
}

int main() {
    Derived d;
    Func(d);  // "Base"가 출력됨 (slicing 발생)
}
  • 예시 2. 해결 방법 (포인터 또는 참조 사용)
void Func(Base& b) {  // ✅ 참조를 사용하면 slicing 방지
    b.Print();
}

Inheritance

모든 상속(inheritance)은 public 으로 선언되어야 한다.

  • private 상속을 수행하려면 기본 클래스의 인스턴스를 구성원으로 대신 포함
  • 기본 클래스로 사용하는 것을 지원하지 않을 경우 final 키워드를 클래스 앞에 선언

상속의 사용을 "is-a"의 경우로 제한한다.

  • "Bar가 Foo의 한 종류" 라고 합리적으로 말할 수 있어야 함

인터페이스(interface) 상속은 virtual 클래스로 부터의 상속을 말한다.

  • 그 외는 구현(Implementation) 상속이라고 말함

하위 클래스에서 액세스해야 할 수 있는 멤버 함수로 protected의 사용을 제한한다.

다중 상속은 허용되지만 다중 구현 상속은 권장되지 않는다.

Access Control

상수가 아닌 경우 클래스의 데이터 멤버를 private으로 선언한다.

Declaration order

유사한 선언을 그룹화하고 public 부분을 먼저 배치한다.

클래스의 정의는 일반적으로 public: 섹션으로 시작하고 그 다음에 protected:, private: 가 따라와야 한다.

  • 비어 있는 섹션은 생략함

다음 순서를 선호한다.

  1. Types and type aliases (typedef, using, enum, nested structs and classes, and friend types)
  2. (Optionally, for structs only) non-static data members
  3. Static constants
  4. Factory functions
  5. Constructors and assignment operators
  6. Destructor
  7. All other functions (static and non-static member functions, and friend functions)
  8. All other data members (static and non-static)
반응형

Cursor : There was error while Renaming: "tools":

반응형

요즘은 CLion 보다 Cursor를 쓰고 있다.

보통 CLion, ChatGPT를 켜놓고 작업을 하는데, Cursor는 이 둘을 합친 효과가 난다.

그리고 최근 발표한 클로드 3.7 모델도 바로 써볼 수 있다. (큰 차이는 없음)

 

그러다 이번주 수요일쯤, 갑자기 오류 메세지가 뜨며 Cursor가 켜지지 않았다.

그리고 이어지는 오류 메세지를 보니,

업데이트를 하다 문제가 생긴 것 같았다.

Failed to install Cursor update

 

곧장 커뮤니티로 가서 update라고 검색해보았다.

https://forum.cursor.com/t/cursor-windows-update/55355

 

Cursor Windows Update

When update is downloaded and I press to restart to update i get an error. I don’t see any Cursor instances run in task manager, when I try to repeat the same error appears. If I cancel installation I won’t be able to launch cursor anymore. And the fun

forum.cursor.com

 

갑작스러운 상황에 유저들은 실시간으로 본인도 안된다고 댓글을 달기 시작했고,

커서 개발진은 업데이트 버그 고칠때까지 공홈에서 낮은 버전을 다운받아서 사용해달라고 했다.

0.45.15를 쓰세요

 

어느 유저는 이제 업데이트를 누르기 무섭다고 한다.

실제 Update Cursor? 저 창만 눌러도 업데이트가 진행되기 때문이다.

이래도 업데이트 할래?

 

언제쯤 고쳐주려나..

반응형

+ 최근 글