The value is an abstract concept. A value is associated with a set of realizations that characterize or identifies the value. For example with a value of 10$ one could buy a book or a meal.
A value can have multiple representations. For example the 10$ can be represented by coins or stored as bits in a bank account.
An object is to a value what a bank account is to a quantity of money: the object (/the bank account) holds the representation of the value (/10$). This is described in [basic.types]:
The value representation of an object of type T is the set of bits that participate in representing a value of type T.
Bits in the object representation that are not part of the value representation are padding bits.
Then in [intro.object] it is specified that an object is associated to a region of storage:
An object occupies a region of storage in its period of construction ([class.cdtor]), throughout its lifetime, and in its period of destruction ([class.cdtor]).
This distinction between the object and its value is more sensible if we consider an abstract machine with a central processor unit, that performs operations, and a separated memory where can be stored objects (that holds value representation). When an operation is performed on a value, the value is loaded into different cpu registers. So the value in the cpu does not have the same representation: a contiguous sequence of bits as it had inside the object. Moreover any cpu is free to represent the value in a register as best suit its need.
When the cpu executes an operation, it does it on a piece of value stored in a register. After that operation is performed, the cpu can save the result in memory, inside an object, or continue to operate on the value.
The decomposition of an operation in operations on values and in storages or loads from or to objects, appears in the standard:
a load is an lvalue-to-rvalue conversion [conv.lvalue] A glvalue of a non-function, non-array type T can be converted to a prvalue.
all operations in c++ will result in a sequence of fundamental operations with built-in meaning. Most of these operations applies on value (prvalue) and not on an object. Before these operations are performed lvalue-to-rvalue is applied [expr] Whenever a glvalue expression appears as an operand of an operator that expects a prvalue for that operand, the lvalue-to-rvalue,[...]
the results of these built-in operations, that operate on value, are always prvalue (a prvalue is just a value not associated to any object). Then the resulting value can be used as operand of an other built-in operation, or initialize an object (a store operation in the memory of our machine), [basic.lval]:A prvalue is an expression whose evaluation initializes an object or a bit-field, or computes the value of the operand of an operator, as specified by the context in which it appears. So in our machine representation, the act of storing the value in an object is a store.
To illustrate this, let's analyze this simple piece of code:
int main(int argc, char* argv[]){
int j = 2*argc+1;
}
2*argc built-in operator * is called with two arguments 2 and argc. argc is an lvalue, so lvalue-to-rvalue is applied. The value of argc is loaded in a cpu register (2 could be an immediate) and the multiply operation is performed.
- the result of
2*argc is a prvalue, that is directly used as the first operand (2*argc)+(argc). Then the resulting prvalue of this last operation is used to initialize the object j: the resulting value is stored in the memory representation of j.