cpp_2_4_指针 Pointer_4_传地址 Pass by address

  1. Overview
  2. Pass by address 传地址
  3. Null checking 空指针检查
  4. Prefer pass by (const) reference 仍然选择传递 (const) 引用

Overview

1.Pass by address 传地址
2.Null checking 空指针检查
3.Prefer pass by (const) reference 仍然选择传递 (const) 引用

Pass by address 传地址

1.我们之前学习函数参数传递左值引用, 可以避免额外的 copy 开销; 回顾下引用本质上是一种绑定关系, 没有产生新的东西
2.除了 pass by value, pass by reference, cpp还有一种 pass by address 的方法可以实现参数传递
3.pass by address 仍然也是不传递 object 参数, 而是通过指针来传递 object address, 所以参数传递效率很高

#include<iostream>
#include<string>

void printByValue(std::string val) {
  std::cout << val << "\n";
}

void printByReference(const std::string& ref) {
  std::cout << ref << "\n";
}

void printByAddress(const std::string* ptr) {
  std::cout << *ptr << "\n";
}

int main() {
  std::string str{"hello world"};
  printByValue(str);
  printByReference(str);
  printByAddress(&str);  // 注意这里要取到地址, 因此传递的是 &str
  return 0;
}

我们可以使用传递地址的方式传递参数, 并且通过 dereference 的方式修改值

#include <iostream>
void changeValue(int* ptr) {
  *ptr = 6;
}

void changeValue2(const int* ptr) {
             // 会报错
  *ptr = 7;  // 如果是设定成const int*指针, 也就是指向int 类型的 const value的指针, 那就不能修改值了
}

int main() {
  int x{5};
  std::cout << "x = " << x << '\n';
  changeValue(&x);
  std::cout << "x = " << x << '\n';
  return 0;
}

结果

x = 5
x = 6

Null checking 空指针检查

1.我们在函数参数中采用了指针类型参数, 但是指针有指向为空的问题, 我们看下下面的例子, 会导致 crash

#include <iostream>
void print(int* ptr) {
  std::cout << *ptr << '\n';
}

int main() {
  int x{5};
  print(&x);
  int* myPtr{};
  print(myPtr);
  std::cout << "hello";
  return 0;
}

经过指针的检查, 在 dereference 之前我们确认是一个非空指针

#include <iostream>

void print(int* ptr) {
  if (ptr) {
    std::cout << *ptr << '\n';
  }
}

int main() {
    int x{5};
    print(&x);
    print(nullptr);
  int y{};
  print(&y);
  std::cout << "hello";
    return 0;
}

Prefer pass by (const) reference 仍然选择传递 (const) 引用

In modern C++, most things that can be done with pass by address are better accomplished through other methods. Follow this common maxim: “Pass by reference when you can, pass by address when you must”.

First, because an object being passed by address must have an address, only lvalues can be passed by address (as rvalues don’t have addresses). Pass by const reference is more flexible, as it can accept lvalues and rvalues:

Second, the syntax for pass by reference is natural, as we can just pass in literals or objects. With pass by address, our code ends up littered with ampersands (&) and asterisks (*).

intuitively,
1.一种最佳实践: 只要能传递引用解决问题, 那么就传递引用; 传递地址, 只允许发生在非要用传递地址解决的情形下, 因为传递引用比传递地址犯错的可能性更小
2.为什么传递引用比传递地址犯错的可能性更小? 有 2 点原因如下:
(i). 通过地址传递的object, 必须是有个地址的, 左值以传递地址, 右值不传递任何地址; 如果是传递的是 const 引用 那就更灵活了, 能处理左值也能接受右值
(ii). 传递引用的语法更加的自然

#include <iostream>
void printByValue(int val) {
  std::cout << val << '\n';
}
void printByReference(const int& ref) {
  std::cout << ref << '\n';
}
void printByAddress(const int* ptr) {
  std::cout << *ptr << '\n';
}
int main() {
  printByValue(5);     // 直接传值
  printByReference(5); // const 引用左值和右值都能传递
  printByAddress(&5);  // 不能传递右值
  return 0;
}

转载请注明来源, from goldandrabbit.github.io

💰

×

Help us with donation