Force C++ to assign new addresses to arguments

≡放荡痞女 提交于 2021-01-28 06:10:43

问题


It seems that when I pass different integers directly to a function, C++ assigns them the same address as opposed to assigning different addresses to different values. Is this by design, or an optimization that can be turned off? See the code below for an illustration.

#include <iostream>

const int *funct(const int &x) { return &x; }

int main() {

  int a = 3, b = 4;
  // different addresses
  std::cout << funct(a) << std::endl;
  std::cout << funct(b) << std::endl;

  // same address
  std::cout << funct(3) << std::endl;
  std::cout << funct(4) << std::endl;
}

The bigger context of this question is that I am trying to construct a list of pointers to integers that I would add one by one (similar to funct(3)). Since I cannot modify the method definition (similar to funct's), I thought of storing the address of each argument, but they all ended up having the same address.


回答1:


The function const int *funct(const int &x) takes in a reference that is bound to an int variable.

a and b are int variables, so x can be bound to them, and they will have distinct memory addresses.

Since the function accepts a const reference, that means the compiler will also allow x to be bound to a temporary int variable as well (whereas a non-const reference cannot be bound to a temporary).

When you pass in a numeric literal to x, like funct(3), the compiler creates a temporary int variable to hold the literal value. That temporary variable is valid only for the lifetime of the statement that is making the function call, and then the temporary goes out of scope and is destroyed.

As such, when you are making multiple calls to funct() in separate statements, the compiler is free to reuse the same memory for those temporary variables, eg:

// same address
std::cout << funct(3) << std::endl;
std::cout << funct(4) << std::endl;

Is effectively equivalent to this:

// same address
int temp;
{
temp = 3;
std::cout << funct(temp) << std::endl;
}
{
temp = 4;
std::cout << funct(temp) << std::endl;
}

However, if you make multiple calls to funct() in a single statement, the compiler will be forced to make separate temporary variables, eg:

// different addresses
std::cout << funct(3) << std::endl << funct(4) << std::endl;

Is effectively equivalent to this:

// different addresses
{
int temp1 = 3;
int temp2 = 4;
std::cout << funct(temp1) << std::endl << funct(temp2) << std::endl;
}

Demo




回答2:


The function

const int *funct(const int &x) { return &x; }

will return the address of whatever x is referencing.

So this will, as you expected, print the address of a:

std::cout << funct(a) << std::endl;

The problem with the expression funct(3) is that it is impossible to make a reference of a constant and pass it as a parameter. A constant doesn't have an address, and therefore for practical reasons C++ doesn't support taking a reference of a constant. What C++ actually does support is making a temporary object, initializing it with the value 3, and taking the reference of that object.

Basically, the compiler will, in this case, translate this:

std::cout << funct(3) << std::endl;

into something equivalent to this:

{
  int tmp = 3;
  std::cout << funct(tmp) << std::endl;
}

Unless you do something to extend the lifetime of a temporary object, it will go out of scope after the function call (or right before the next sequence point, I am not sure).

Since the temporary created by 3 goes out of scope before you create a temporary from 4, the memory used by the first temporary may be reused for the second temporary.



来源:https://stackoverflow.com/questions/65332620/force-c-to-assign-new-addresses-to-arguments

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!