1

Aliasing is the main optimization issue with pass-by-const-reference functions that take multiple arguments; this has been pointed out in answers to similar questoins. However, this particular answer also seems to suggest that the compiler can make more assumptions about a single-argument pass-by-value function than an otherwise identical pass-by-const-reference function.

This would imply that pass-by-value is the preferred strategy for small objects. While this seems like perfectly sound logic for an argument of a non-class type or a type with a constexpr copy constructor, I fail to see how these assumptions could be extended to an argument that does not meet these requirements. Take the following example:

foo.h

#ifndef FOO_H
#define FOO_H

struct Foo {
    int i;
    Foo(int i);
    Foo(const Foo &other);
    ~Foo();
};

void incrementNewestFoo();

#endif

foo.cpp

#include "foo.h"
#include <algorithm>
#include <vector>

std::vector<Foo *> foos;

Foo::Foo(int i) : i(i) {
    foos.push_back(this);
}

Foo::Foo(const Foo &other) : i(other.i) {
    foos.push_back(this);
}
Foo::~Foo() {
    foos.erase(std::find(foos.cbegin(), foos.cend(), this));
}

void incrementNewestFoo() {
    foos.back()->i += 1;
}

main.cpp

#include "foo.h"
#include <iostream>

using namespace std;

void passByValue(Foo foo) {
    cout << foo.i << endl;
    incrementNewestFoo();
    cout << foo.i << endl;
}

void passByConstReference(const Foo &foo) {
    cout << foo.i << endl;
    incrementNewestFoo();
    cout << foo.i << endl;
}

int main() {
    Foo foo(0);
    passByValue(foo);
    passByConstReference(foo);
}

As far as I'm aware, the behavior of main() is well-defined according to the C++ standard. According to the previously linked answer, the most valuable assumption to be made about the pass-by-value function is that the value of i will not change between reads in most cases. However, it appears to me as though this assumption is invalid for any call to a function whose definition resides in another compilation unit (except for const member functions for which the pass-by-const-reference function can make the same assumption anyway). Perhaps I am missing something?

QuaternionsRock
  • 832
  • 7
  • 14
  • The compiler cannot assume `incrementNewestFoo()` will leave `foo.i` unchanged in either function. In `passByConstReference()` all the `const` does is cause the compiler to diagnose attempts in the function to *change* non-mutable` state of `foo` or obtain a non-`const` reference or pointer to `foo`. The compiler cannot routinely assume that the caller has not stored a non-`const` reference/pointer to the object it passes somewhere else, nor can it assume that `incrementNewestFoo()` doesn't modify that object by some other means - which, coincidentally, is exactly what your code does. – Peter Oct 09 '21 at 08:53
  • @Peter sorry if I wasn't clear, but that's exactly what I'm trying to point out with my example. To rephrase my question: is there anything that can be assumed about a pass-bt-value function that can't be assumed about a pass-by-const-reference function? [I see the suggestion that pass-by-value is often faster everywhere](https://stackoverflow.com/a/7456816/3451226), but I don't see how that could be possible. – QuaternionsRock Oct 11 '21 at 05:23

0 Answers0