Practice/C & C++

C++에서 언제 어떻게 struct를 사용하는가?

C++로 코딩할 때에 class와 struct 중에 무엇을 사용할 지 고민을 할 때가 있다.
내가 C++에서 struct를 선택하는 기준은 다음과 같다.

  • 분해하면 모든 멤버 변수가 scala data type이다.
    멤버 변수가 scala data type이거나, 조건에 부합하는 compound data type이어야 한다.
    compound data type은 고정 길이 array, union, struct 이며, 위 조건을 만족한다.
    여기에 해당이 안되면, 즉, 포인터나 가변 길이 배열, class를 포함하고 있다면 class를 사용한다.
  • 구조체를 이진 데이타로 고스란히 pack/unpack 해야 한다.
    struct는 메모리 형태 그대로 데이터로 상호 변환 가능함으로 개발하기 편하다.
    굳이 별도의 pack/unpack 함수를 작성할 필요가 없다.
    이와 같은 용도의 struct를 만들 때에는, 데이터 구조체 정렬(data structure alignment)를 주의한다.[각주:1]
  • 모든 멤버 변수를 외부에 공개할 수 있다.
    반대로 외부에 공개할 필요가 없는-예를 들여, 구현의 변경에 따라서 얼마든지 바뀔 수 있는 구현 의존적인- 멤버 변수가 있다면 class로의 구현을 고민한다.[각주:2]


비록 C++의 struct가 기본 접근 속성이 다른 class의 변종 정도지만,
되도록 C의 그것과 동일한 의미로 사용되도록 작성하는 편이다.
그렇게 하기 위해서는 아래 제약 사항을 지켜야 한다.

  • 상속(inheritance)을 받지 않았다.
    상속은 메모리 구성을 보장하지 않는다.
    상속이 필요하면 구성(composition)으로 해결한다.
    상속받을 struct를 대개 첫번째 멤버 변수로 등록한다.
  • 멤버 함수를 만들지 않는다.
    생성, 초기화, 복사, 할당은 대개 변수의 선언이나 메모리 초기화/복사 등으로 구현한다.
    다른 연관 함수들은 전역 함수 내지는 별도의 구현 class를 이용하여 작성한다.


  1. 이에 관해서는 "<a href="http://unipro.tistory.com/197" target="_blank">C언어에서 struct 정의 그대로 이진 데이터로 만들기</a>"를 참고한다. [본문으로]
  2. 외부 공개용 struct와 내부 구현용 struct/class로 분리하는 전략도 있음으로 반드시 class를 선택할 필요는 없다. [본문으로]
저작자 표시 변경 금지
신고
  1. Favicon of http://moneycoach.kr/ 소액결제 현금화 M/D Reply

    관리자의 승인을 기다리고 있는 댓글입니다

Practice/Lisp

Lisp 비교 : Emacs의 개발 환경

공통 설정

(require 'package)
(add-to-list 'package-archives
             '("melpa" . "https://melpa.org/packages/"))
(add-to-list 'package-archives
             '("melpa-stable" . "http://melpa-stable.milkbox.net/packages/"))
(setq package-enable-at-startup nil)
(setq package-archive-priorities '(("melpa-stable" . 1)))
(package-initialize)

;; Bootstrap `use-package'
(unless (package-installed-p 'use-package)
  (package-refresh-contents)
  (package-install 'use-package))

(setq use-package-verbose t)
(setq use-package-always-bin "melpa-stable")

(eval-when-compile
  (require 'use-package))

(use-package paredit
  :ensure t
  :diminish paredit-mode
  :init
  (use-package paredit-everywhere
    :ensure t))


Common Lisp

Common Lisp의 major-mode는 'lisp-mode'이다.
보통 확장자 '*.lisp'나 '*.l'와 연결되어 있다.[각주:1]
SLIME이라는 강력한 REPL 도구가 있다.

Common Lisp 설정 예[각주:2]:

(add-hook 'lisp-mode-hook (lambda ()
                            (setq indent-tabs-mode nil)
                            (paredit-mode t)
                            (helm-gtags-mode 1)))

(use-package slime
  :ensure t
  :commands slime
  :init
  (setq inferior-lisp-program (or (executable-find "sbcl")
                                  (executable-find "/usr/bin/sbcl")
                                  (executable-find "/usr/local/bin/sbcl")
                                  "sbcl"))
  :config
  (require 'slime-autoloads)
  (slime-setup '(slime-fancy))
  (add-hook 'slime-repl-mode-hook (lambda () (paredit-mode t))))


Scheme

Scheme의 major-mode는 'scheme-mode'이다.
확장자 '*.scm'을 사용하면 이 모드와 자동으로 연결된다.
Common Lisp의 SLIME에 비슷한 것으로는 geiser가 있다.

Scheme 설정 예:

(add-hook 'scheme-mode-hook (lambda ()
                              (setq indent-tabs-mode nil)
                              (paredit-mode t)
                              (helm-gtags-mode 1)))

(use-package geiser
  :ensure t
  :init
  (setq geiser-active-implementations '(guile))
  (setq geiser-guile-binary (or (executable-find "guile")
                                (executable-find "/usr/bin/guile")
                                (executable-find "/usr/local/bin/guile")
                                "guile")))


Clojure

최근 주목받고 있는 Lisp 변종인 Clojure의 major-mode는 'clojure-mode'이다.
'*.clj' 파일을 열거나 만들면 이 모드에서 작업할 수 있다.
Clojure 역시 CIDER라는 강력한 REPL 도구를 제공한다.

Clojure 설정 예:

(use-package clojure-mode
  :ensure t
  :init
  (use-package flycheck-clojure
    :ensure t
    :config (flycheck-clojure-setup))
  :config
  (add-hook 'clojure-mode-hook (lambda ()
                                 (setq indent-tabs-mode nil)
                                 (paredit-mode t)
                                 (subword-mode t))))

(use-package cider
  :ensure t
  :commands (cider cider-connect cider-jack-in)
  :config
  (add-hook 'cider-mode-hook 'eldoc-mode)
  (add-hook 'cider-repl-mode-hook (lambda ()
                                    (paredit-mode t)
                                    (subword-mode t))))


Emacs Lisp

emacs는 emacs lisp로 만들어졌음으로 당연히 훌륭한 major 모드를 제공한다.
'*.el', '.elisp' 또는 '.emacs' 파일을 열면 자동으로 'emacs-lisp-mode'에 들어간다.
'ielm'은 Emacs Lisp를 위한 훌륭한 REPL 도구이다.

Emacs Lisp 설정 예:

(add-hook 'emacs-lisp-mode-hook (lambda ()
                                  (setq indent-tabs-mode nil)
                                  (turn-on-eldoc-mode)
                                  (eldoc-add-command
                                   'paredit-backward-delete
                                   'paredit-close-round)
                                  (paredit-mode t)))
(add-hook 'lisp-interaction-mode-hook (lambda () (paredit-mode t)))
(add-hook 'ielm-mode-hook (lambda () (paredit-mode t)))


  1. 명시적인 지정이 없으면 파일의 확장자(auto-mode-alist 변수에 명시된 확장자)나 내용(shebangs, magic-mode-alist 명시된 파일의 내용 패턴)을 보고 자동으로 major-mode를 결정한다. [본문으로]
  2. 나의 Emacs 설정 파일 Github: <a href="http://github.com/unipro/.emacs.d">http://github.com/unipro/.emacs.d</a> [본문으로]
저작자 표시 변경 금지
신고
Life/Society

진짜는 굳이 의미를 부여할 필요가 없다.

얼마 전 꿈에서 내가 나한테

진짜는 굳이 의미를 부여할 필요가 없다.

고 말했다.[각주:1]
꿈의 통찰에 완전히 감탄했다.

가짜는 본질의 회피하기 위해서 다양한 의미를 부여해야 한다.
뭔가 설명이 필요하고 더구나 설명이 복잡하면 그건 본질이 아니다.

누군가의 관계에 꼭 의미를 붙여야만 한다면 진정한 만남이 아니다.
자신이 하는 일에 이런 저런 이유가 필요하다면 분명히 그른 일이다.
나의 감정/느낌/생각에 대한 설명이 길어진다면 거짓을 꾸미고 포장하는 것이다.[각주:2]

진짜는 짧고 단순하고 명쾌하다.
추가되는 내용이 있다면 단지 부연하는 것 뿐이다.
덧붙이지 않아도 아무런 상관이 없다.

가짜는 온갖 부차적인 이유와 설명이 꼭 필요하다.
진실의 강력함을 감추기 위해서 수많은 부연이 수반된다.

  1. 꿈이 훨씬 통찰력이 있다고 생각되었다. 깨어있을 때는 자아의 온갖 방어 기제가 거짓을 말하기 때문에 듣지 못한 것 같다. [본문으로]
  2. 거짓임을 자각하지 못할 수도 있다. [본문으로]
저작자 표시 변경 금지
신고
Life/Society

사람을 믿는 기준

도덕과 윤리에서 사람을 믿고 도움을 줘야 한다라고 배웠다.
아무나 어떤 상황에서도 믿어야 할까?
무조껀 신뢰하는 것은 항상 불신하는 것만큼이나 어리석다.
이 글에서 믿음의 기준에 대해서 탐구하고자 한다,

상대방이 반격하더라도 막아낼 수 있다면 웬만하면 믿음을 가져라.
그러나, 나를 지킬 수 없을 것 같으면 상대방에 대한 믿음보다 자신을 보호하는 것이 우선이다.
상대방의 반격을 막아낼 능력이 없으면 관용적인 자세는 실효성이 없다.

"나 못 믿어?"
"속고만 살았어?"

별의 별 소리를 해도
만에 하나 있을 수 있는
상대의 공격을 막을 수 없다면 믿는 것은 위험하다.

"사람을 믿고 열린 자세로 가져야 합니다."

라는 도덕적/종교적인 지침에도 이는 적용된다.

이런 이유로 집에 혼자 있는 아이나 여성은
아는 사람이라고 하더라도
자신보다 강하다면
함부로 집에 들어오게 하면 안된다.

어린이가 택배 기사의 방문에 대문을 열어주지 않는 것은
그분이 나쁜 사람이라서가 아니라
자신을 지킬 수 없기 때문이다.

반면, 처음보는 사람이라도
나를 지켜낼 수 있다면 배척할 필요는 없다.

믿음의 조건은 상대방이 아닌 자신에게 달렸다.

저작자 표시 변경 금지
신고
Theory/Project Management

일단 만들어라. 두 번 만들어라. 그러면 보일 것이다.

내가 실무에서 배운 최고의 설계 방법은?
일단 만들어라. 두 번 만들어라. 그러면 보일 것이다.


문제를 이해하는 가장 좋은 방법은 만들어보는 것이다.
생각만으로는 알 수 없다.
구현하면서 문제에 대한 이해가 높아진다.


첫번째 구현에서는 문제의 탐색에 초점을 두어야 한다.
머릿속에 떠오르는 이상적인 시나리오를 직선적으로 표현한다.
성능, 보안, 유연성, 예외 처리, 우아한 코드, 추상화 등은 전혀 고려하지 않는다.


그림에 비유하자면, 머릿속에 떠오른 이미지를 거침없이 스케치를 하는 것과 같다.
화폭에 그리면서 이야기와 구도를 잡는 것이 가장 효과적이다.
이 단계에서는 세세한 부분에 신경쓰지 않는다.


종종 문제 탐색이란 목적을 잊고 멋진 코드를 만드는데 집중하는 실수를 하곤 한다.
문제의 탐색이 늦어지면 그만큼 손해다.
프로젝트 중반에 드러나는 설계의 문제는 치명적이다.


그림의 구도를 파악하기도 전에 세세한 묘사에 빠지는 것과 같다.
어느정도 그림을 완성한 후에 문제를 발견하면 고치는데 상당한 비용이 든다.


이때 "문제만 탐색하고 버릴 코드"라는 생각이 도움이 된다.
우리는 버릴 것에는 공을 들이지 않는다.


위 단계를 원하는 설계가 나올 때까지 반복한다.[각주:1]
이전에 얻은 교훈은 다음번 탐색 구현에서 적용한다.
설계가 명확해지면 탐색을 멈춘다.
이제 본격적인 구현에 들어간다.


  1. 보통 두세번이면 충분하다. 더 이상 반복해도 그다지 나아지지 않는다. 투자한 시간과 노력보다 얻는 이익이 적다. [본문으로]
저작자 표시 변경 금지
신고

알림

이 블로그는 구글에서 제공한 크롬에 최적화 되어있고, 네이버에서 제공한 나눔글꼴이 적용되어 있습니다.

카운터

Today : 6
Yesterday : 105
Total : 174,450