У меня проблема с созданием одного тривиального проекта C ++ с использованием лямбда-выражений и общих указателей для работы.Проект находится в Visual Studio, Debug, x64.Вот код, который у меня есть.
Class1.h:
#pragma once
#include <functional>
class Class1
{
int m_data;
const int* m_data_ptr;
public:
std::function<int(int)> m_func;
Class1(int, int);
void Assign(const int&);
};
Class2.h:
#pragma once
#include "Class1.h"
class Class2
{
Class1 m_class1obj;
public:
Class2(int, int);
void Assign(const int&);
int Compute(int);
};
main.cpp:
#include <iostream>
#include "Class1.h"
#include "Class2.h"
Class1::Class1(int i, int j) : m_data(j), m_data_ptr(nullptr)
{
m_func = [i, this](int x)
{
int val = *m_data_ptr;
return (val + m_data + i)*x;
};
std::cout << "Creating class1 object!\n";
}
void Class1::Assign(const int& v)
{
m_data_ptr = &v;
}
Class2::Class2(int i, int j) : m_class1obj(i, j)
{
std::cout << "Creating class2 object!\n";
}
void Class2::Assign(const int& v)
{
m_class1obj.Assign(v);
}
int Class2::Compute(int v)
{
return m_class1obj.m_func(v);
}
int main()
{
int val = 4;
/*
Class2 class2obj(3, 5);
class2obj.Assign(val);
std::cout << class2obj.Compute(23.0) << std::endl;
*/
std::shared_ptr<Class2> class2_ptr;
class2_ptr = std::make_shared<Class2>(Class2(3, 5));
class2_ptr->Assign(val);
std::cout << class2_ptr->Compute(23) << std::endl;
}
Код компилируется нормально, но вылетает при выполнении последней строки main()
.Во время отладки я обнаружил, что проблема обнаруживается после завершения строки class2_ptr = std::make_shared<Class2>(Class2(3, 5));
. По какой-то причине, когда лямбда в строке m_func = ...
захватывает указатель this
во время создания объекта Class1
, он записывает адрес, который становится другимс адреса объекта сразу после создания умного указателя для Class2
!Кажется, первый записанный адрес устарел.Когда я вызываю class2_ptr->Compute(23)
, я в конечном итоге разыменовываю нулевой указатель на int val = *m_data_ptr;
, что приводит к сбою, хотя я назначил ненулевой адрес в class2_ptr->Assign(val);
до вызова m_func
!Но почему изменился адрес this
?Это из-за внутреннего перераспределения объекта в памяти, скрытого от пользователя?Если так, почему компилятор не переназначил правильное значение this
в хранилище m_func
?Кроме того, несмотря на неправильный адрес объекта Class1
, записанный в m_func
, доступ к другому элементу данных m_data
осуществляется с правильным значением в m_func
.
Важная вещь заключается в том, что если я закомментирую последние четыре строки в main () и удалю комментарии для остальных трех строк, программа не завершится сбоем!Понятно, что использование общего указателя как-то связано с этим.Есть ли проблема в неправильном использовании лямбда-выражений или умных указателей в этом случае?Кажется, я не могу найти объяснение в стандарте C ++ для моей ситуации.
Спасибо за все комментарии, объясняющие, что происходит!