Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.syntblaze.com/llms.txt

Use this file to discover all available pages before exploring further.

A value parameter (or pass-by-value) is a parameter-passing mechanism where a function receives an independent instance of the argument provided by the caller. Any modifications made to the parameter within the function’s scope are strictly local to that function and do not mutate the original argument in the calling environment.
#include <string>

void processData(int number, std::string text) {
    number = 100;       // Modifies local copy only
    text = "Modified";  // Modifies local copy only
}

Initialization and Execution Mechanics

When a function is invoked with a value parameter, the C++ standard abstract machine dictates the following sequence of operations:
  1. Initialization: The parameter is copy-initialized from the caller’s argument.
    • For fundamental types (e.g., int, double, pointers), the compiler performs standard copy initialization. Depending on the Application Binary Interface (ABI) and the specific type, this may involve passing the value directly in a CPU register rather than allocating memory.
    • For user-defined types (e.g., class, struct) passed as lvalues, the compiler invokes the type’s copy constructor (T::T(const T&)) to initialize the local parameter using the caller’s object.
  2. Destruction: Upon function termination, the local parameter’s lifetime ends. For user-defined types, the destructor (T::~T()) is invoked on the local instance.
class Widget {
public:
    Widget() {}
    Widget(const Widget& other) { /* Copy constructor invoked */ }
    ~Widget() { /* Destructor invoked on function exit */ }
};

void inspectWidget(Widget w) {
    // 'w' is a distinct instance initialized via Widget's copy constructor
}

Object Slicing

A critical technical implication of value parameters in C++ is object slicing. If a function parameter is defined as a base class passed by value, and the caller passes a derived class object, the compiler will only invoke the base class’s copy constructor. The resulting local parameter will be a pure base class object. All derived-class member variables are discarded (sliced off), and polymorphic behavior (virtual function resolution) is lost because the dynamic type of the copy is strictly the base type.
class Base { 
public: 
    virtual void print() {} 
};

class Derived : public Base { 
public: 
    void print() override {} 
    int extraData; 
};

void evaluate(Base b) {
    // 'b' is strictly a Base object. 
    // 'extraData' is sliced off. Virtual dispatch to Derived::print is impossible.
}

Move Semantics and Copy Elision

Value parameters interact directly with move semantics and copy elision rules. The initialization behavior changes depending on the value category of the argument provided by the caller:
  • Lvalues: Passing an lvalue invokes the copy constructor, duplicating the underlying resources.
  • Xvalues (Explicit Moves): If the caller passes an xvalue (e.g., an explicitly moved object via std::move), the compiler invokes the move constructor (T::T(T&&)). The underlying resources are transferred to the value parameter rather than duplicated.
  • Prvalues (Temporaries): Since C++17, mandatory copy elision (guaranteed copy elision) dictates that passing a prvalue (such as a temporary object) directly initializes the parameter in place. Neither the copy constructor nor the move constructor is invoked, completely bypassing any overhead.
#include <string>
#include <utility>

void processString(std::string s) {
    // 's' owns the string data
}

int main() {
    std::string data = "Resource";
    
    // 1. Lvalue: Invokes copy constructor; 'data' remains intact.
    processString(data); 
    
    // 2. Xvalue: Invokes move constructor; 'data' is left in a valid but unspecified state.
    processString(std::move(data)); 
    
    // 3. Prvalue: Mandatory copy elision (C++17+); 's' is initialized directly in place.
    // Neither the copy nor move constructor is called.
    processString(std::string("Temporary")); 
    
    return 0;
}
Master C++ with Deep Grasping Methodology!Learn More