What would be the point of defining constructor methods within the class below?
The output of the called functor within the transformation in the main function is the same irrespective of the user-defined constructors.
A course on templates and the STL utilizes this code as an example of transformations but the constructors are included, which I think are unnecessary.
The objective of the functor is to capitalize the first character in each string passed but it would not function properly based on the implementation herein if the constructor methods are actually utilized/called.
The default constructor is called once (and _last initialized) if the commented code is included, so the parametrized constructor and _sep are not utilized. The code runs fine without the constructors and the if statement but apparently that may cause UB?
Are there scenarios where the parametrized constructor and the functor would be called simultaneously or sequentially?
With no explicit constructors, the class has implicit default constructor.
The _last has no initializer and is therefore default initialized (with undetermined value) by the default constructor.
The _sep has default initializer and has thus value 0 after construction.
The (first call to) operator() uses the undetermined _last and therefore its result is UB.
If you add the custom constructor title_case(constchar), then no default constructor will be created automatically.
In order to have both, you need to define the default constructor.
Yes I noticed the copy constructor is called when the transform algorithm is called but wanted to find a way to prevent this from occurring so the state of the object instance that is passed is modified directly.
The appropriate cppreference page will tell you the header file that declares std::ref, and which C++ standard version introduced it: https://en.cppreference.com/w/cpp/utility/functional/ref
To summarize, it's part of the <functional> header since C++11.
mbozzi wrote:
Be careful ...
darnoceloc wrote:
I noticed the copy constructor is called when the transform algorithm is called but wanted to find a way to prevent this from occurring so the state of the object instance that is passed is modified directly.
I only suggest general caution. It's a relatively common error to assume too much about what (any) library does with a stateful function object.
Why does std::ref need to be used in this scenario, why can’t the standard reference assignment identifier be used to create a reference to the function object and pass it to the transform algorithm. Would the algorithm create a copy of that function object reference that does not also reference the original object function object that was passed by reference?
I’ve seen examples in which a separate state class was defined outside of the function class then declared as a member variable of the function class. The constructor of the function class is then defined to take a reference object to the state class as a parameter which is utilized to initialize the state object that was already declared as a member variable. Essentially passing the state object by reference ‘inside’ the function object.
By ‘standard reference identifier’ I mean, declaring Funct &obj prior to call of algorithm , then pass obj to std. algorithm. Instead of declaring Funct obj, then passing std::ref(obj). What is the difference in those two approaches, is it due to the copy-constructible and copy-assignable attributes of the reference wrapper?
You've fallen for a common misconception: "my code works, therefore it is correct."
The truth is that your code works by accident, not by design.
_last is uninitialized, so it could contain any value that happens to be there. If it contained anything but zero, the first character would not be capitalized.
I mean, declaring Funct &obj prior to call of algorithm.
There's no possible way to do anything with or learn anything about a reference itself. All operations performed to a reference are applied to the referenced object:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
Funct f1;
Funct& rf1 = f1; // must initialize
Funct& rf2 = rf1; // rf1 is indistinguishable from f1
// rf1 and rf2 name the same object
Funct f2 = rf2; // rf2 is indistinguishable from f1
// f2 is a copy of f1.
// size of a reference is the size of the referent
static_assert(sizeof (char&) == sizeof (char));
static_assert(sizeof (f1) == sizeof (rf2));
// address of a reference is the address of the referent
assert(&rf1 == &f1);
// etc.
This is why the proposed solution won't work: C++'s reference variables are referentially transparent. References merely assign a new name to the referenced object; there is no way to do anything with the reference itself. Attempting to copy it will copy the referenced value.
std::ref returns a reference_wrapper. The standard library will copy that reference_wrapper however much it wants. However, each copy still refers to the same function object.
We would say that std::reference_wrapper does not maintain value semantics because it makes object identity important.
So the reference is essentially just another alias via which a value can be accessed but the reference wrapper class (emulator of aforementioned reference) allows the alias to be copied instead of the value being referred.
Not so. A reference to title_case behaves identically to the title_case it aliases. Every title_case is copy/move-constructible and copy/move-assignable.
The standard provides complete referential transparency. References do nothing but alias existing objects, every operation on a reference operates on the aliased object. Attempting to move from a reference will attempt to move from the referenced value.
The distinction between move/copy isn't very relevant here.
std::reference_wrapper can be copy-constructed and copy-assigned, but instead of copy-constructing or copy-assigning the stored object, it copies a pointer (typically a pointer) to the object it refers to.
The effect is that distinct copies of reference_wrapper<title_case> refer to the same title_case with the same internal state, whereas distinct copies of title_case are independent objects with duplicate internal state.