c++ - 通过 std::reference_wrapper 行为不一致的纯虚函数的运行时多态调用

标签 c++ c++11 std reference-wrapper run-time-polymorphism

我向你展示了这个谜题:

使用这个编译器:

user@bruh:~/test$ g++ --version

g++ (Ubuntu 7.3.0-16ubuntu3) 7.3.0 Copyright (C) 2017 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

...和这个编译字符串:

g++ main.cpp class.cpp -o main -g

...和这些文件:

类.hpp:

class base {

  public:

    base();

    virtual void f() = 0;
};

class derived : public base {

  public:

    derived( unsigned int id );

    void f() override;

    unsigned int id; 
};

类.cpp:

#include <iostream>

#include "class.hpp"

base::base() {

  return;
}

derived::derived( unsigned int id )
  :
  id( id ),
  base() {

  return;
}

void derived::f() {

  std::cout << "Ahoy, Captain! I am " << id << std::endl;

  return;
}

主要.cpp:

#include <iostream>
#include <functional>
#include <vector>

#include "class.hpp"

int main() {

  unsigned int n_elements;

  std::cout << "enter the number of elements: ";

  std::cin >> n_elements;

  std::cout << std::endl;

  std::vector< class derived > v;

  std::vector< std::reference_wrapper< class base > > base_vector_0;

  std::vector< std::reference_wrapper< class base > > base_vector_1;

  for( unsigned int i = 0; i < n_elements; i++ ) {

    v.emplace_back( i );

    base_vector_0.emplace_back( v[ i ] );
  }

  for( unsigned int i = 0; i < n_elements; i++ ) {

    base_vector_1.emplace_back( v[ i ] );
  }

  std::cout << "sanity check:" << std::endl;

  for( unsigned int i = 0; i < n_elements; i++ ) {

    class base &base = v[ i ];

    base.f();
  }

  std::cout << "case 1:" << std::endl;

  for( unsigned int i = 0; i < n_elements; i++ ) {

    base_vector_1[ i ].get().f();
  }

  std::cout << "case 0:" << std::endl;

  for( unsigned int i = 0; i < n_elements; i++ ) {

    base_vector_0[ i ].get().f();
  }

  return 0;
}

...我得到以下输出:

user@bruh:~/test$ ./main
enter the number of elements: 1

sanity check:
Ahoy, Captain! I am 0
case 1:
Ahoy, Captain! I am 0
case 0:
Ahoy, Captain! I am 0
harrynh3@bruh:~/test$ ./main
enter the number of elements: 2

sanity check:
Ahoy, Captain! I am 0
Ahoy, Captain! I am 1
case 1:
Ahoy, Captain! I am 0
Ahoy, Captain! I am 1
case 0:
Segmentation fault (core dumped)

我的问题:

  1. 当用户提供的参数 = 1 时,为什么这不是段错误

  2. 当用户提供的参数 > 1 时,为什么会出现此段错误

我对代码作用的简短解释:

创建许多从抽象基类派生的对象。将对容器中对象的引用存储为围绕抽象基类引用的 std::reference_wrapper。创建 std::reference_wrapper 的容器略有不同。通过 std::reference_wrappers 调用纯虚函数的派生覆盖。上面源代码中指定的情况下的段错误。

恳求C++高手们...请帮帮我!这很有趣,我不知道为什么会这样!我可能做了一些愚蠢的事情。

最佳答案

您在这段代码中创建了悬挂引用:

  for( unsigned int i = 0; i < n_elements; i++ ) {

    v.emplace_back( i ); // [1]

    base_vector_0.emplace_back( v[ i ] ); // [2]
  }

[1] 添加新项目,[2] 存储对该项目的引用。如果在调用 emplace_back 时 vector 被重新调用,则所有引用都将无效并且您引用的项目不存在。 vector 在通过向其中添加新项目超过其当前容量时重建。

如果您想将 n_elements 精确地存储在 v vector 中并避免重建 vector ,您可以调用 reserve:

  std::vector< class derived > v;
  v.reserve(n_elements); // added

  std::vector< std::reference_wrapper< class base > > base_vector_0;

  std::vector< std::reference_wrapper< class base > > base_vector_1;

  for( unsigned int i = 0; i < n_elements; i++ ) {

    v.emplace_back( i );

    base_vector_0.emplace_back( v[ i ] );
  }

现在,当 emplace_back 被调用时,没有引用是无效的,并且通过 base_vector_0 访问这些引用是安全的。

关于c++ - 通过 std::reference_wrapper 行为不一致的纯虚函数的运行时多态调用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54939146/

相关文章:

c++ - 好的多线程指南?

c++ - 通过取消引用 NULL 指针来分配引用

c++ - 从构造函数抛出后调用析构函数

c++ - 热处理 c++11 lambda,同时捕获此指针并指定调用约定

c++ - std::vector 的 setter

c++ - 在C++中查找范围的长度

c++ - 什么是 RtlPcToFileHeader?

c++ - 将使用 VC++10 编译的代码链接到使用 VC++9 编译的代码

c++ - 是否有任何有效的用例可以在现代 C++ 中使用 new 和 delete、原始指针或 c 样式数组?

c++ - Visual C++、std 和 getline(ifstream, string)、EOF 在 std 堆栈内抛出和中断,这正常吗?