c++ - Function pointers point to identical address values? ...sometimes - Stack Overflow

I have an array of function pointers and I want to assign simple dummy functions.The first thing that

I have an array of function pointers and I want to assign simple dummy functions.

The first thing that came to my mind was using lambda. That worked pretty well. The only thing that surprised me was the fact that I get different pointer addresses when I assign them one by one, but get identical addresses when I do it in a loop.

#include <iostream>

int main()
{

    int (*ptrArr[6])(void);
    int size = sizeof(ptrArr)/sizeof(void*);

    // results in three different pointer addresses
    ptrArr[0] = [](){return 0;};
    ptrArr[1] = [](){return 0;};
    ptrArr[2] = [](){return 0;};

    // results in three identical pointer addresses
    for(int i = 3; i < size; i++)
    {
        ptrArr[i] = [](){return 0;};
    }

    for(int i = 0; i < 6; i++)
    {
        std::cout << (void*)ptrArr[i] << std::endl;
    }

    return 0;
}

Output:

00E9F810
00E9F840
00E9F870
00E9F8A0
00E9F8A0
00E9F8A0

Is there a way to get different instances of the dummy functions using the loop?

I also tried some constructions using std::function<>, but didn't get it assigned to the function pointers.

I have an array of function pointers and I want to assign simple dummy functions.

The first thing that came to my mind was using lambda. That worked pretty well. The only thing that surprised me was the fact that I get different pointer addresses when I assign them one by one, but get identical addresses when I do it in a loop.

#include <iostream>

int main()
{

    int (*ptrArr[6])(void);
    int size = sizeof(ptrArr)/sizeof(void*);

    // results in three different pointer addresses
    ptrArr[0] = [](){return 0;};
    ptrArr[1] = [](){return 0;};
    ptrArr[2] = [](){return 0;};

    // results in three identical pointer addresses
    for(int i = 3; i < size; i++)
    {
        ptrArr[i] = [](){return 0;};
    }

    for(int i = 0; i < 6; i++)
    {
        std::cout << (void*)ptrArr[i] << std::endl;
    }

    return 0;
}

Output:

00E9F810
00E9F840
00E9F870
00E9F8A0
00E9F8A0
00E9F8A0

Is there a way to get different instances of the dummy functions using the loop?

I also tried some constructions using std::function<>, but didn't get it assigned to the function pointers.

Share Improve this question edited Mar 6 at 22:44 halfer 20.4k19 gold badges109 silver badges202 bronze badges asked Mar 6 at 19:10 JensJens 333 bronze badges 9
  • why does the address of the lambda matter ? – Ahmed AEK Commented Mar 6 at 19:14
  • 2 Is there an actual problem you're trying to solve, or is this a curiosity question? – Stephen Newell Commented Mar 6 at 19:14
  • Maybe you should watch CppCon 2017: Matt Godbolt “What Has My Compiler Done for Me Lately? Unbolting the Compiler's Lid”. Your "problem" isn't described in it... but you can learn how "smart" compilers are in finding patterns in your code and using those patterns to generate as less code as they can and still produce the correct output (as long as you don't have UB) – Pepijn Kramer Commented Mar 6 at 19:17
  • 1 Re: int size = sizeof(ptrArr)/sizeof(void*); -- there is no guarantee that void* is the same size as a pointer to function. The usual way to do this would be sizeof(ptrArr)/sizeof(*ptrArr). But you already know the size of your array: it's 6. If you don't throw away that information you don't have to figure out how to get it back. – Pete Becker Commented Mar 6 at 19:19
  • A side note similar to Pete's point above: Use std::size. – user4581301 Commented Mar 6 at 19:20
 |  Show 4 more comments

3 Answers 3

Reset to default 5

you can use a function template to generate multiple dummy unique functions.

#include <iostream>
#include <array>

template <size_t N>
int func() { return N; }

int main()
{
    constexpr size_t functions_count = 6;

    using func_type = int (*)(void);
    static constexpr auto ptrArr = 
      []<size_t...Ints>(std::integer_sequence<std::size_t, Ints...>)
      {
        return std::array<func_type,sizeof...(Ints)>{&func<Ints>...};
      }(std::make_integer_sequence<size_t,functions_count>{});

    for(int i = 0; i < functions_count; i++)
    {
        std::cout << (void*)ptrArr[i] << std::endl;
    }

    return 0;
}
0x58e668ea51d0
0x58e668ea51e0
0x58e668ea51f0
0x58e668ea5200
0x58e668ea5210
0x58e668ea5220

online demo

the size needs to be known at compile time.

i think the variadic lambda is C++20, for lower versions use a free function instead. demo

The reason the pointers sometimes are equal and sometimes not becomes much clearer if you replace the lambda expressions with free functions :

#include <iostream>

int fooA() { return 0; };
int fooB() { return 0; };
int fooC() { return 0; };
int fooD() { return 0; };

int main()
{

    int (*ptrArr[6])(void);
    int size = sizeof(ptrArr)/sizeof(*ptrArr);

    // results in three different pointer addresses
    ptrArr[0] = fooA;
    ptrArr[1] = fooB;
    ptrArr[2] = fooC;

    // results in three identical pointer addresses
    for(int i = 3; i < size; i++)
    {
        ptrArr[i] = fooD;
    }

    for(int i = 0; i < 6; i++)
    {
        std::cout << (void*)ptrArr[i] << std::endl;
    }

    return 0;
}

Each time you write the expression [](){return 0;}; you create a new hidden function, then for each loop iteration your function pointer is assigned to that same function. Even if you loop over that lambda expression multiple times, it is only defined once. In the same way getting the address of fooD repeatedly should always give the same pointer, getting the address of one [](){return 0;} will also always give the same pointer.

A lambda creates a distinct class type with an overloaded operator(). A non-capturing lambda is convertible to a function pointer that invokes the same code as that operator.

In your first use-case, you are creating 3 separate lambda instances, and they are remaining in scope until main() exits. That is 3 separate objects in memory at the same time. The compiler may recognize that they are doing the same thing and optimize them into a single instance, but that is unlikely. So, you end up seeing 3 separate addresses being used.

In your second use-case, you are creating and destroying a single lambda instance on every loop iteration. There is only 1 object in memory at a time, so the compiler is free to reuse the same memory for each object.

发布者:admin,转转请注明出处:http://www.yc00.com/questions/1744954923a4603135.html

相关推荐

发表回复

评论列表(0条)

  • 暂无评论

联系我们

400-800-8888

在线咨询: QQ交谈

邮件:admin@example.com

工作时间:周一至周五,9:30-18:30,节假日休息

关注微信