요즘은 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? 저 창만 눌러도 업데이트가 진행되기 때문이다.

이래도 업데이트 할래?

 

언제쯤 고쳐주려나..

유튜브를 해보겠다고 야심차게 구독했던 어도비,

당분간은 못할 것 같아서 취소를 하기로 마음먹었다.

 

adobe에 로그인하고 오른쪽 상단에 프로필을 누른다.

그리고 계정 관리를 클릭한다.

우측 계정 관리 클릭

 

좌측 하단에 플랜 관리를 누른다. 

플랜 관리

 

그리고 플랜 변경을 선택한다.

플랜 취소

 

그럼 지금 쓰는 것보다 싼 라이트룸 플랜을 선택한다.

플랜 선택

기존 어도비 요금제가 선택한 것보다 비싼거여서 부분 환불을 해준다.

인증단계로 진행

 

그럼 이제 변경되었다.

 

 

그리고 한 30분정도 있으면,

아까 플랜 관리에서 취소 버튼이 생긴다.

취소하자!

 

그럼 이제 취소가 된다.

 

조기 취소 수수료 없이 해지 완료!

Scoping

Namespaces

대부분의 코드가 합리적으로 짧은 이름을 사용할 수 있도록 하는 동시에 이름 충돌을 방지하는 방법을 제공한다.

  • 몇가지 예외를 제외하고는 네임스페이스에 코드를 배치한다
  • 가능한 프로젝트 이름과 경로를 기준으로 고유한 이름을 가져야 한다.
  • 아래 예제와 같이 주석을 달아 네임스페이스 종료를 알린다.
// In the .h file
namespace mynamespace {
 
// All declarations are within the namespace scope.
// Notice the lack of indentation.
class MyClass {
 public:
  ...
  void Foo();
};
 
}  // namespace mynamespace
// In the .cc file
namespace mynamespace {
 
// Definition of functions is within scope of the namespace.
void MyClass::Foo() {
  ...
}
 
}  // namespace mynamespace
  • inline namespace를 가급적 사용하지 않고, 꼭 사용해야한다면 아래의 예시처럼 default 인식에 주의한다.
    • 버전 관리같은 의도된 default 동작은 예외
    namespace CAR {
    namespace VER1 {
    class ElectricCar; // VER1 Class
    }  // namespace VER1
    
    inline namespace VER2 {
    class ElectricCar; // VER2 Class
    }  // namespace VER2
    
    class GasCar;
    
    }  // namepsace CAR
    
    // CAR::VER2::ElectricCar, VER2가 inline namespace이기 때문에 CAR namespace로 간주
    CAR::ElectricCar* car1;
    CAR::VER1::ElectricCar* car2;
    CAR::VER2::ElectricCar* car3;
    
  • using namespace 사용에 주의한다.
// Forbidden -- This pollutes the namespace.
using namespace foo;

// Shorten access to some commonly used names in .cc files.
namespace baz = ::foo::bar::baz;

 

Internal Linkage

함수, 변수 등이 해당 소스 파일(.cc)에서만 사용될 경우, 다른 파일에서 접근하지 못하도록 내부 연결을 부여한다.

  • Unnamed namespace 사용
namespace {
    int internalVar = 42;  // 다른 파일에서 접근 불가능
    void internalFunction() {
        // ...
    }
}  // namespace
  • static 키워드 사용
static int internalVar = 42;  // 다른 파일에서 접근 불가능
static void internalFunction() {
    // ...
}

내부 연결은 헤더 파일에서는 사용하 안된다.

  • 각각의 소스 파일에서 서로 다른 복사본이 생성되기 때문

Nonmember, Static Member, and Global Functions

비 멤버 함수와 정적 멤버 함수, 글로벌 함수의 적절한 사용이 필요하다.

  • 클래스에 속하지 않은 함수, Nonmember function 는 네임스페이스 안에 넣는다.
  • 글로벌 함수보다 네임스페이스를 활용한다.
  • 예시 1. 글로벌 네임스페이스의 오염
#include <iostream>

void PrintMessage() {  // 전역(global) 네임스페이스에 있음
    std::cout << "Hello, world!" << std::endl;
}
  • 예시 2. 올바른 예
#include <iostream>

namespace utils {
    void PrintMessage() {
        std::cout << "Hello, world!" << std::endl;
    }
}

int main() {
    utils::PrintMessage();
    return 0;
}

 

  • 정적 멤버 변수를 위한 클래스는 사용하지 않는다.
    • 예시 1. 클래스를 네임스페이스처럼 사용
class Utility {
public:
    static void PrintMessage() {
        std::cout << "Hello, world!" << std::endl;
    }
};

 

  • ODR(One Definition Rule) 문제 발생에 주의한다.
    • 같은 프로그램에서 동일한 이름의 함수가 여러 번 정의되면 컴파일 오류 발생
// file1.cpp
#include <iostream>
void PrintMessage() {  // 글로벌 함수
    std::cout << "Hello from file1!" << std::endl;
}

// file2.cpp
#include <iostream>
void PrintMessage() {  // 글로벌 함수 (중복 정의!)
    std::cout << "Hello from file2!" << std::endl;
}

// ❌ 링크 오류 발생! (ODR 위반)

Local Variables

가능한 가장 좁은 범위에 함수의 변수를 배치하고 선언에서 변수를 꼭 초기화한다.

  • C++ 에서는 함수의 어느 곳에서나 변수를 선언할 수 있다.
  • 처음 사용하는 곳에 가깝게 선언하는 것이 좋다.
    • 선언을 찾고 변수 유형과 초기화 대상을 쉽게 확인할 수 있음
    • 선언 및 할당 대신 초기화를 사용
      std::vector<int> v;
      v.push_back(1);  // Prefer initializing using brace initialization.
      v.push_back(2);
      
      std::vector<int> v = {1, 2};  // Good -- v starts initialized.
      
      std::vector<int> v;
      v.push_back(1);  // Prefer initializing using brace initialization.
      v.push_back(2);
      
      std::vector<int> v = {1, 2};  // Good -- v starts initialized.
  • If, while 및 for 문에 필요한 변수는 일반적으로 해당 statement 내에서 선언되어야 하며, 이러한 변수는 해당 범위로 제한된다.
while (const char* p = strchr(str, '/')) str = p + 1;
  • 변수가 객체인 경우, 해당 루프 외부에서 선언하는 것이 더 효율적이다.
// Inefficient implementation:
for (int i = 0; i < 1000000; ++i) {
  Foo f;  // My ctor and dtor get called 1000000 times each.
  f.DoSomething(i);
}

Foo f;  // My ctor and dtor get called once each.
for (int i = 0; i < 1000000; ++i) {
  f.DoSomething(i);
}

 

Static and Global Variable

정적 저장 수명(static storage duration)을 가진 객체는 프로그램이 시작될 때부터 종료될 때까지 존재하는 객체이다. 이러한 객체는 아래와 같은 경우에 생성된다.

  • 네임스페이스 수준의 전역 변수(global variable)
  • 클래스의 static 멤버 변수
  • 정적 함수 지역 변수(static function-local variable)
// 네임스페이스 스코프 (전역 변수)
const int globalValue = 42;  

// 클래스의 static 멤버 변수
class MyClass {
    static int classStaticVar;
};

// 함수 내부의 static 변수
void foo() {
    static int localStaticVar = 10;
}

이러한 변수들은 종료시 소멸되지만 여러 가지 문제를 유발할 수 있다.

  • 예시 1. 나쁜 예
// bad: non-trivial destructor
const std::string kFoo = "foo";

// Bad for the same reason, even though kBar is a reference (the
// rule also applies to lifetime-extended temporary objects).
const std::string& kBar = StrCat("a", "b", "c");

void bar() {
  // Bad: non-trivial destructor.
  static std::map<int, int> kData = {{1, 0}, {2, 0}, {3, 0}};
}
  • 예시 2. 좋은 예
const int kNum = 10;  // Allowed

struct X { int n; };
const X kX[] = {{1}, {2}, {3}};  // Allowed

void foo() {
  static const char* const kMessages[] = {"hello", "world"};  // Allowed
}

// Allowed: constexpr guarantees trivial destructor.
constexpr std::array<int, 3> kArray = {1, 2, 3};

thread_local Variables

thread_local 지정자를 사용하여 변수를 선언할 수 있다.

thread_local Foo foo = ...;

네임스페이스 범위, 함수 내부 또는 정적 클래스 멤버로 선언할 수 있지만 일반 클래스 멤버로는 선언할 수 없다.

  • 이러한 변수는 실제로 객체의 모임이므로 다른 스레드가 접근 할 때 실제로 다른 객체에 액세스 한다.
  • 변수 인스턴스는 프로그램 시작 시 한 번이 아니라 각 스레드에 대해 별도로 초기화되어야 한다는 점을 제외하고는 정적 변수와 매우 유사하게 초기화된다.
  • 즉, 함수 내에 선언된 thread_local 변수는 안전하지만 다른 thread_local 변수는 정적 변수(와 그 외)와 동일한 초기화 순서 문제의 영향을 받는다.
  • thread_local 변수 인스턴스들은 스레드가 종료되기 전에 소멸되지 않으므로 정적 변수의 소멸 순서 문제가 없다.

+ Recent posts