Skip to content

Types, Values, and References

C++ types determine valid operations, representation requirements, overload selection, object lifetime rules, and generic constraints.

Fundamental and compound types

Fundamental types include Boolean, character, integer, floating-point, and void. Exact widths are not universal for types such as int and long; use fixed-width types such as std::int32_t only when the implementation provides them and the exact width is part of the contract.

Compound types include arrays, functions, pointers, references, classes, enumerations, and pointer-to-member types.

int value = 42;
int* pointer = &value;       // may be reseated; can be null
int& reference = value;      // aliases value; must be initialized
int const& view = value;     // read-only access through this reference

const restricts mutation through a particular access path; it does not prove that no other alias can mutate the object. Logical constness may permit carefully synchronized caches through mutable, but indiscriminate mutation violates client expectations.

Value categories

Expressions have a type and a value category. The primary categories are:

  • lvalue: identifies an object or function with persistent identity;
  • xvalue: identifies an object whose resources may be reused;
  • prvalue: computes a value used to initialize an object or operand.

These categories influence reference binding, overload resolution, temporary materialization, copying, and moving. “Everything is either on the stack or heap” is not the C++ object model.

Initialization

int count{0};
std::string title{"Algorithms"};
auto length = title.size();

Brace initialization rejects many narrowing conversions. auto deduces a type from the initializer; it does not make C++ dynamically typed. Check deduction when references, top-level const, proxy types, or initializer lists matter.

Conversions

Implicit conversions can change sign, range, precision, or overload selection. Mixed signed/unsigned arithmetic is a frequent source of surprising comparisons. Prefer conversions that state intent and validate values before narrowing.

Named casts have distinct meanings:

  • static_cast requests a checked-at-compile-time language conversion;
  • dynamic_cast performs supported runtime checks in polymorphic hierarchies;
  • const_cast changes cv-qualification but cannot make a truly const object mutable;
  • reinterpret_cast performs low-level reinterpretations with narrow valid uses.

Views and lifetime

std::span<T> views contiguous elements; std::string_view views character data. Neither normally owns the referenced storage.

std::string_view invalid_view() {
    std::string local{"temporary"};
    return local; // dangling view after local is destroyed
}

Every non-owning view requires a lifetime argument: the referenced object must outlive every use of the view.

Exercises

  1. Explain the difference between int const*, int* const, and int const* const.
  2. Find the lifetime defect in a function returning a view of local storage.
  3. Explain why auto preserves static typing.