Namespaces
Variants

Object

From cppreference.net
C++ language
General topics
Flow control
Conditional execution statements
Iteration statements (loops)
Jump statements
Functions
Function declaration
Lambda function expression
inline specifier
Dynamic exception specifications ( until C++17* )
noexcept specifier (C++11)
Exceptions
Namespaces
Types
Specifiers
constexpr (C++11)
consteval (C++20)
constinit (C++20)
Storage duration specifiers
Initialization
Expressions
Alternative representations
Literals
Boolean - Integer - Floating-point
Character - String - nullptr (C++11)
User-defined (C++11)
Utilities
Attributes (C++11)
Types
typedef declaration
Type alias declaration (C++11)
Casts
Memory allocation
Classes
Class-specific function properties
Special member functions
Templates
Miscellaneous

C++ 프로그램은 객체 를 생성, 파괴, 참조, 접근 및 조작합니다.

객체는 C++에서

다음 개체들은 객체가 아닙니다: 값, 참조, 함수, 열거자, 타입, 비정적 클래스 멤버, 템플릿, 클래스 또는 함수 템플릿 특수화, 네임스페이스, 매개변수 팩, 그리고 this .

변수 는 비정적 데이터 멤버가 아닌, 선언 에 의해 도입된 객체나 참조입니다.

목차

객체 생성

객체는 정의 , new 표현식 , throw 표현식 , union 의 활성 멤버 변경, 그리고 임시 객체 를 필요로 하는 표현식 평가를 통해 명시적으로 생성될 수 있습니다. 생성된 객체는 명시적 객체 생성에서 고유하게 정의됩니다.

암시적 수명 타입 의 객체들은 다음에 의해서도 암시적으로 생성될 수 있습니다

  • 상수 평가 중이 아닌 경우를 제외하고, unsigned char 또는 std::byte (C++17부터) 타입의 배열 수명이 시작되는 연산에서, 이러한 객체들이 배열 내에 생성됩니다,
  • 다음 할당 함수 호출에서, 이러한 객체들이 할당된 저장 공간에 생성됩니다:
(C++17부터)
(C++20부터)
  • 다음 특정 함수들을 호출하는 경우, 이 경우 해당 객체들은 지정된 저장 영역에 생성됩니다:
  • std::start_lifetime_as
  • std::start_lifetime_as_array
(since C++23)

프로그램에 정의된 동작을 부여하는 한, 동일한 저장 영역에 0개 이상의 객체가 생성될 수 있습니다. 이러한 생성이 불가능한 경우(예: 충돌하는 연산으로 인해) 프로그램의 동작은 정의되지 않습니다. 여러 개의 이러한 암시적으로 생성된 객체 집합이 프로그램에 정의된 동작을 부여할 수 있다면, 어떤 객체 집합이 생성되는지 명시되지 않습니다. 즉, 암시적으로 생성된 객체가 고유하게 정의될 필요는 없습니다.

지정된 저장 영역 내에서 객체를 암묵적으로 생성한 후, 일부 연산은 적합하게 생성된 객체 에 대한 포인터를 생성합니다. 적합하게 생성된 객체는 저장 영역과 동일한 주소를 가집니다. 마찬가지로, 프로그램에 정의된 동작을 제공할 수 있는 포인터 값이 존재하지 않는 경우에만 동작이 정의되지 않으며, 프로그램에 정의된 동작을 제공하는 여러 값이 존재할 경우 어떤 포인터 값이 생성되는지 명시되지 않습니다.

#include <cstdlib>
struct X { int a, b; };
X* MakeX()
{
    // 가능한 정의된 동작 중 하나:
    // std::malloc 호출은 암시적으로 X 타입의 객체와
    // 그 서브객체 a와 b를 생성하고, 해당 X 객체에 대한 포인터를 반환합니다
    X* p = static_cast<X*>(std::malloc(sizeof(X)));
    p->a = 1;
    p->b = 2;
    return p;
}

std::allocator::allocate 호출 또는 union 타입의 암시적으로 정의된 복사/이동 특수 멤버 함수도 객체를 생성할 수 있습니다.

객체 표현과 값 표현

일부 타입과 객체는 object representations value representations 를 가지며, 이들은 아래 표에 정의되어 있습니다:

엔티티 객체 표현 값 표현
완전한 객체 타입 T T 타입의 비트 필드가 아닌 완전한 객체가 차지하는 N unsigned char 객체들의 시퀀스, 여기서 N sizeof ( T ) T 타입의 값을 표현하는 데 참여하는 T 의 객체 표현 내 비트들의 집합
T 타입의 비트 필드가 아닌 완전한 객체 obj T 의 객체 표현에 해당하는 obj 의 바이트들 T 의 값 표현에 해당하는 obj 의 비트들
비트 필드 객체 bf bf 가 차지하는 N 비트들의 시퀀스, 여기서 N 은 비트 필드의 너비임 bf 의 값을 표현하는 데 참여하는 bf 의 객체 표현 내 비트들의 집합

타입이나 객체의 객체 표현에서 값 표현의 일부가 아닌 비트들은 패딩 비트 입니다.

TriviallyCopyable 타입의 경우, 값 표현(value representation)은 객체 표현(object representation)의 일부입니다. 이는 저장소에서 객체가 차지하는 바이트들을 복사하는 것만으로 동일한 값을 가진 다른 객체를 생성할 수 있음을 의미합니다(단, 객체가 잠재적으로 중첩되는 부분 객체(subobject)이거나, 값이 해당 타입의 trap representation 이며 이를 CPU에 로드할 때 SNaN("signalling not-a-number") 부동소수점 값이나 NaT("not-a-thing") 정수와 같은 하드웨어 예외가 발생하는 경우는 제외).

대부분의 구현에서는 트랩 표현(trap representation), 패딩 비트(padding bits), 또는 정수 타입에 대한 다중 표현(multiple representations)을 허용하지 않지만, 예외가 있습니다; 예를 들어 Itanium의 정수 타입 값은 트랩 표현일 수 있습니다 .

역은 반드시 참이 아닙니다: 서로 다른 객체 표현을 가진 TriviallyCopyable 타입의 두 객체가 동일한 값을 나타낼 수 있습니다. 예를 들어, 여러 부동 소수점 비트 패턴이 동일한 특수 값 NaN 을 나타낼 수 있습니다. 더 일반적으로는 패딩 비트가 정렬 요구 사항 , 비트 필드 크기 등을 충족시키기 위해 도입될 수 있습니다.

#include <cassert>
struct S
{
    char c;  // 1바이트 값
             // 3바이트 패딩 비트 (alignof(float) == 4 가정)
    float f; // 4바이트 값 (sizeof(float) == 4 가정)
    bool operator==(const S& arg) const // 값 기반 동등성 비교
    {
        return c == arg.c && f == arg.f;
    }
};
void f()
{
    assert(sizeof(S) == 8);
    S s1 = {'a', 3.14};
    S s2 = s1;
    reinterpret_cast<unsigned char*>(&s1)[2] = 'b'; // 일부 패딩 비트 수정
    assert(s1 == s2); // 값은 변경되지 않음
}

char , signed char , 그리고 unsigned char 타입의 객체들에 대해 (과다 크기의 비트 필드 가 아닌 경우), 객체 표현의 모든 비트는 값 표현에 참여해야 하며, 가능한 모든 비트 패턴은 서로 다른 값을 나타내야 합니다 (패딩 비트, 트랩 비트 또는 다중 표현이 허용되지 않음).

서브오브젝트

객체는 하위 객체(subobjects) 를 가질 수 있습니다. 여기에는 다음이 포함됩니다

  • 멤버 객체
  • 기본 클래스 서브객체
  • 배열 요소

다른 객체의 하위 객체가 아닌 객체를 완전 객체(complete object) 라고 합니다.

완전한 객체, 멤버 하위 객체, 또는 배열 요소가 class type 인 경우, 그 타입은 기반 클래스 하위 객체의 클래스 타입과 구분하기 위해 most derived class 로 간주됩니다. most derived class 타입의 객체 또는 비클래스 타입의 객체는 most derived object 라고 불립니다.

클래스의 경우,

이를 잠재적으로 생성된 서브객체 라고 합니다.

크기

서브오브젝트는 베이스 클래스 서브오브젝트이거나 [[ no_unique_address ]] 속성으로 선언된 비정적 데이터 멤버인 경우 (C++20부터) 잠재적으로 중첩되는 서브오브젝트 입니다.

객체 obj 가 오직 다음과 같은 모든 조건을 만족할 때에만 크기가 0일 가능성이 있습니다:

  • obj 는 잠재적으로 중첩되는 하위 객체입니다.
  • obj 는 가상 멤버 함수와 가상 기반 클래스가 없는 클래스 타입입니다.
  • obj 는 크기가 0이 아닌 하위 객체를 가지지 않거나 이름 없는 비트 필드 의 길이가 0이 아닌 경우가 없습니다.

위의 모든 조건을 만족하는 객체 obj 에 대해:

  • 만약 obj 가 비정적 데이터 멤버가 없는 standard-layout (since C++11) 클래스 타입의 기본 클래스 하위 객체인 경우, 이는 크기가 0입니다.
  • 그렇지 않은 경우, obj 가 크기가 0인 상황은 구현에 따라 정의됩니다.

자세한 내용은 empty base optimization 를 참조하십시오.

크기가 0이 아닌 모든 비트 필드가 아닌 객체는 하나 이상의 바이트 저장 공간을 차지해야 하며, 여기에는 해당 객체의 하위 객체들에 의해 (전체 또는 일부로) 점유되는 모든 바이트가 포함됩니다. 객체가 trivially copyable 또는 standard-layout (since C++11) 타입인 경우, 점유된 저장 공간은 연속적이어야 합니다.

주소

객체가 비트 필드(bit-field)가 아니거나 크기가 0인 하위 객체가 아닌 경우, 해당 객체의 주소 는 객체가 차지하는 첫 번째 바이트 의 주소입니다.

객체는 다른 객체를 포함할 수 있으며, 이 경우 포함된 객체는 이전 객체 내에 중첩된 것입니다. 다음 조건 중 하나라도 충족되면 객체 a 가 다른 객체 b 내에 중첩됩니다:

  • a b 의 하위 객체입니다.
  • b 저장소를 제공합니다 a 에 대해.
  • 객체 c 가 존재하여, a c 내에 중첩되고, c b 내에 중첩됩니다.

객체는 다음 객체 중 하나인 경우 잠재적으로 고유하지 않은 객체 입니다:

(C++11부터)
  • 잠재적으로 고유하지 않은 객체의 하위 객체.

비트 필드가 아닌 두 객체의 수명 이 겹치는 경우:

  • 다음 조건 중 하나라도 충족되면 동일한 주소를 가질 수 있습니다:
  • 둘 중 하나가 다른 하나 내에 중첩되어 있습니다.
  • 둘 중 하나가 크기가 0인 하위 객체이며, 해당 유형들이 유사(similar) 하지 않습니다.
  • 둘 모두 잠재적으로 고유하지 않은 객체입니다.
  • 그렇지 않으면, 항상 서로 다른 주소를 가지며 저장소의 겹치지 않는 바이트를 차지합니다.
// 문자 리터럴은 항상 고유함
static const char test1 = 'x';
static const char test2 = 'x';
const bool b = &test1 != &test2;      // 항상 true
// "r", "s", "il"에서 접근하는 문자 'x'는
// 동일한 주소를 가질 수 있음 (즉, 이 객체들이 저장 공간을 공유할 수 있음)
static const char (&r) [] = "x";
static const char *s = "x";
static std::initializer_list<char> il = {'x'};
const bool b2 = r != il.begin();      // 지정되지 않은 결과
const bool b3 = r != s;               // 지정되지 않은 결과
const bool b4 = il.begin() != &test1; // 항상 true
const bool b5 = r != &test1;          // 항상 true

다형성 객체

적어도 하나의 가상 함수를 선언하거나 상속하는 클래스 타입의 객체는 다형성 객체입니다. 각 다형성 객체 내부에서 구현체는 (모든 현존 구현에서 최적화되지 않는 한 하나의 포인터입니다) 추가 정보를 저장하며, 이 정보는 가상 함수 호출과 RTTI 기능( dynamic_cast typeid )에 의해 사용되어, 객체가 사용된 표현식과 무관하게 런타임에 객체가 생성된 타입을 결정합니다.

다형성이 없는 객체의 경우, 값의 해석은 객체가 사용된 표현식에 따라 결정되며 컴파일 시간에 결정됩니다.

#include <iostream>
#include <typeinfo>
struct Base1
{
    // 다형성 타입: 가상 멤버 선언
    virtual ~Base1() {}
};
struct Derived1 : Base1
{
     // 다형성 타입: 가상 멤버 상속
};
struct Base2
{
     // 비다형성 타입
};
struct Derived2 : Base2
{
     // 비다형성 타입
};
int main()
{
    Derived1 obj1; // Derived1 타입으로 생성된 object1
    Derived2 obj2; // Derived2 타입으로 생성된 object2
    Base1& b1 = obj1; // b1은 obj1 객체를 참조
    Base2& b2 = obj2; // b2는 obj2 객체를 참조
    std::cout << "Expression type of b1: " << typeid(decltype(b1)).name() << '\n'
              << "Expression type of b2: " << typeid(decltype(b2)).name() << '\n'
              << "Object type of b1: " << typeid(b1).name() << '\n'
              << "Object type of b2: " << typeid(b2).name() << '\n'
              << "Size of b1: " << sizeof b1 << '\n'
              << "Size of b2: " << sizeof b2 << '\n';
}

가능한 출력:

Expression type of b1: Base1
Expression type of b2: Base2
Object type of b1: Derived1
Object type of b2: Base2
Size of b1: 8
Size of b2: 1

엄격한 별칭 지정

객체를 생성 시 사용된 타입이 아닌 다른 타입의 표현식을 사용하여 접근하는 것은 많은 경우에서 정의되지 않은 동작입니다. 예외 사항과 예제 목록은 reinterpret_cast 를 참조하십시오.

정렬

모든 객체 타입 정렬 요구 사항 이라는 속성을 가지며, 이는 음수가 아닌 정수 값(타입 std::size_t , 그리고 항상 2의 거듭제곱)으로서 이 타입의 객체가 할당될 수 있는 연속된 주소 사이의 바이트 수를 나타냅니다.

타입의 정렬 요구 사항은 alignof 또는 std::alignment_of 로 조회할 수 있습니다. 포인터 정렬 함수 std::align 은 일부 버퍼 내에서 적절하게 정렬된 포인터를 얻는 데 사용할 수 있습니다. std::aligned_storage 은 적절하게 정렬된 저장 공간을 얻는 데 사용할 수 있습니다. (C++23 이전)

(C++11 이후)

각 객체 타입은 해당 타입의 모든 객체에 대해 정렬 요구 사항을 부과합니다 ; 더 엄격한 정렬(더 큰 정렬 요구 사항을 가진)은 alignas 를 사용하여 요청할 수 있습니다 (C++11부터) . 객체 타입의 정렬 요구 사항을 충족하지 않는 저장 공간에 객체를 생성하려는 시도는 정의되지 않은 행동입니다.

클래스의 모든 비정적 멤버들의 정렬 요구사항을 충족시키기 위해, 일부 멤버 뒤에 class , padding bits 가 삽입될 수 있습니다.

#include <iostream>
// S 타입의 객체는 모든 주소에 할당될 수 있음
// S.a와 S.b 모두 모든 주소에 할당될 수 있기 때문
struct S
{
    char a; // 크기: 1, 정렬: 1
    char b; // 크기: 1, 정렬: 1
}; // 크기: 2, 정렬: 1
// X 타입의 객체는 4바이트 경계에 할당되어야 함
// X.n이 4바이트 경계에 할당되어야 하기 때문
// int의 정렬 요구사항은 (보통) 4이기 때문
struct X
{
    int n;  // 크기: 4, 정렬: 4
    char c; // 크기: 1, 정렬: 1
    // 3바이트의 패딩 비트
}; // 크기: 8, 정렬: 4 
int main()
{
    std::cout << "alignof(S) = " << alignof(S) << '\n'
              << "sizeof(S)  = " << sizeof(S) << '\n'
              << "alignof(X) = " << alignof(X) << '\n'
              << "sizeof(X)  = " << sizeof(X) << '\n';
}

가능한 출력:

alignof(S) = 1
sizeof(S)  = 2
alignof(X) = 4
sizeof(X)  = 8

가장 약한 정렬(가장 작은 정렬 요구 사항)은 char , signed char , 그리고 unsigned char 의 정렬로, 이는 1 과 같습니다; 모든 타입의 가장 큰 기본 정렬 은 구현에 따라 정의되며 std::max_align_t 의 정렬과 같습니다 (C++11부터) .

기본 정렬은 모든 종류의 저장 기간을 가진 객체에 대해 지원됩니다.

어떤 타입의 정렬이 std::max_align_t 보다 더 엄격하게(더 크게) alignas 를 사용하여 지정된 경우, 이를 확장 정렬(extended alignment) 요구 사항을 가진 타입이라고 합니다. 정렬이 확장된 타입 또는 비정적 데이터 멤버가 확장 정렬을 가진 클래스 타입은 과잉 정렬(over-aligned) 타입 입니다.

Allocator 타입은 과잉 정렬 타입을 올바르게 처리해야 합니다.

(C++11부터)


new expressions (C++17까지) std::get_temporary_buffer 가 초과 정렬된 타입을 지원하는지는 구현에 따라 정의됩니다.

(C++11부터)
(C++20까지)

참고 사항

C++의 객체는 객체 지향 프로그래밍(OOP) 에서의 객체와는 다른 의미를 가집니다:

C++의 객체 OOP의 객체
모든 객체 타입을 가질 수 있음
(참조: std::is_object )
반드시 클래스 타입을 가져야 함
"인스턴스" 개념이 없음 "인스턴스" 개념이 있음 (그리고 instanceof 와 같은 "인스턴스-관계"를 감지하는 메커니즘이 존재함)
"인터페이스" 개념이 없음 "인터페이스" 개념이 있음 (그리고 instanceof 와 같은 인터페이스 구현 여부를 감지하는 메커니즘이 존재함)
가상 멤버를 통해 명시적으로 다형성을 활성화해야 함 다형성이 항상 활성화됨

결함 보고서 P0593R6 에서는 바이트 배열을 생성하거나 할당 함수 (사용자 정의 가능하며 constexpr 일 수 있음)를 상수 평가 중에 호출할 때 암시적 객체 생성이 발생하는 것으로 고려되었습니다. 그러나 이러한 허용은 상수 평가에서 비결정성을 초래하였으며, 일부 측면에서 바람직하지 않고 구현 불가능한 문제가 있었습니다. 결과적으로 P2747R2 는 상수 평가에서 이러한 암시적 객체 생성을 금지하였습니다. 해당 문서 전체가 결함 보고서는 아니지만, 이러한 변경 사항을 의도적으로 결함 보고서로 취급합니다.

결함 보고서

다음의 동작 변경 결함 보고서들은 이전에 발표된 C++ 표준에 소급 적용되었습니다.

DR 적용 대상 게시된 동작 올바른 동작
CWG 633 C++98 변수는 오직 객체만 가능했음 참조도 가능함
CWG 734 C++98 동일한 값을 보장하는 동일한 스코프에 정의된 변수가
동일한 주소를 가질 수 있는지 여부가 명시되지 않았음
수명이 겹치는 경우 값과 관계없이
주소가 다름이 보장됨
CWG 1189 C++98 동일한 타입의 두 기반 클래스 하위 객체가
동일한 주소를 가질 수 있었음
항상 서로 다른 주소를 가짐
CWG 1861 C++98 좁은 문자 타입의 초대형 비트 필드의 경우,
객체 표현의 모든 비트가 여전히
값 표현에 참여했음
패딩 비트를 허용함
CWG 2489 C++98 char [ ] 는 스토리지를 제공할 수 없지만,
해당 스토리지 내에 객체가 암시적으로 생성될 수 있었음
char [ ] 의 스토리지 내에서 객체가
암시적으로 생성될 수 없음
CWG 2519 C++98 객체 표현의 정의가 비트 필드를 다루지 않았음 비트 필드를 다룸
CWG 2719 C++98 정렬되지 않은 스토리지에서 객체를 생성하는
동작이 불명확했음
이 경우 동작이
정의되지 않음
CWG 2753 C++11 이니셜라이저 리스트의 백업 배열이 문자열 리터럴과
스토리지를 공유할 수 있는지 여부가 불명확했음
스토리지를 공유할 수 있음
CWG 2795 C++98 수명이 겹치는 두 객체가 동일한 주소를 가질 수 있는지
결정할 때, 둘 중 하나가 크기가 0인 하위 객체인 경우
유사한(distinct) 타입을 가질 수 있었음
비유사(non-similar) 타입만 허용함
P0593R6 C++98 이전 객체 모델은 표준 라이브러리에서 요구하는 많은
유용한 관용구를 지원하지 않았고 C의 효과적 타입과
호환되지 않았음
암시적 객체 생성이 추가됨

참고 항목

C 문서 for Object