2

Considering a function:

int f(
        const std::vector<int>& v1,
        const std::vector<int>& v2)
{
    int sum_1 = 0;
    for (int a: v1)
        sum_1 += a;
    int sum_2 = 0;
    for (int a: v2)
        sum_2 += a;
    return std::max(sum_1, sum_2);
}

When calling:

f({5, 7, 9}, {1, 2, 4, 3})

Are these vectors allocated on the heap? If yes, what would be a better design to avoid these allocations?

fontanf
  • 209
  • 1
  • 6
  • 1
    When passed by reference the `vector`s, stay in whatever storage they were allocated in. They are references. They refer to an existing object. – user4581301 Jun 14 '22 at 22:38
  • I would suspect the compiler to detect that they are created when passed and won't be used again afterwards, and do some optimizations because of this – fontanf Jun 14 '22 at 22:40
  • 1
    In `f({5, 7, 9}, {1, 2, 4, 3})` the `vector`s are temporary variables. Handy reading: https://en.cppreference.com/w/cpp/language/lifetime#Temporary_object_lifetime and https://en.cppreference.com/w/cpp/language/reference_initialization#Lifetime_of_a_temporary – user4581301 Jun 14 '22 at 22:41
  • That's a reasonable expectation. [The compiler is allowed to do whatever it wants so long as there are no changes to the observable code](https://en.cppreference.com/w/cpp/language/as_if). In this case a smart enough compiler might be able to reduce all the way to a constant 21. – user4581301 Jun 14 '22 at 22:48
  • 2
    Doesn't seem like any compiler implements such optimization, all of them call `operator new` or `std::vector::vector()`: https://godbolt.org/z/61cMv8rhs – Yksisarvinen Jun 14 '22 at 22:49
  • 2
    Wow. Identical to mine: https://godbolt.org/z/nq54c1ojv Or almost. I threw in a `printf` to make sure the work didn't get completely optimized out. – user4581301 Jun 14 '22 at 22:50
  • 5
    Here: [fully optimized](https://godbolt.org/z/TY5vTfK7c) and it only returns `21`. – Ted Lyngmo Jun 14 '22 at 22:56
  • 2
    @TedLyngmo Good call, works with good old `constexpr` variable too https://godbolt.org/z/9znvvMMqf. – Yksisarvinen Jun 14 '22 at 22:59
  • 1
    @Yksisarvinen Yeah - though, I had to "cheat" and use clang trunk. Clang 14 doesn't accept any of those versions. – Ted Lyngmo Jun 14 '22 at 23:00
  • 2
    Interesting that the compiler's smart enough to do it if you ask, but doesn't volunteer it. I wonder if that's to keep compile time down when it's not explicitly requested. – user4581301 Jun 14 '22 at 23:02
  • 3
    `int f(std::span v1, std::span v2) {...}` called as `f(std::array{5, 7, 9}, std::array{1, 2, 4, 3});` . Requires C++20. Doesn't do memory allocation. – Igor Tandetnik Jun 14 '22 at 23:02
  • The short answer is 'no', but it isn't specified or required. A compiler implementor would have to be mad to engage in `new` and `delete` (and probably `try/catch` to ensure deletion), when he could just allocate the temporaries on the stack and be done with it. – user207421 Jun 15 '22 at 00:05
  • I don't see how duplicate answers this particular question. It doesn't mention classes that manage memory at all. Sure, `std::vector`s will be stored on stack, but their content is not. – Yksisarvinen Jun 15 '22 at 20:13
  • @Yksisarvinen It doesn't have to mention them. Classes that manage memory do whatever they do, whether they are instantiated as temporaries or not. They don't know whether they are temporaries. The salient fact is that the only implementation for temporaries that makes any sense is on the stack, and that's what it says in the duplicate. – user207421 Jun 16 '22 at 00:45

0 Answers0