无法取消引用指针
Unable to dereference pointer
我正在用 C++11 编写 Haskell Maybe Monad 的实现。
但是当我尝试测试代码时卡住了。当我使用伪构造函数 Just
构造一个类型的值,然后尝试使用函数 fromJust
对其进行评估时(应该只是 "unpack" 放置在 Maybe 中的值)程序停止并最终静默终止。
所以我尝试调试它;这是 testMaybe.cpp:
代码的输出
c1
yeih2
value not null: 0xf16e70
我添加了几个打印语句来评估程序停止的位置,它似乎停止在我取消引用指向 return 值的指针的确切位置。 (我已经在代码中标注了。)
起初我认为 maybe 中的值可能在我想取消引用指针时被解构,据我所知,这将导致未定义的行为或终止。但是,我找不到发生这种情况的地方。
你能告诉我为什么会这样吗?
testMaybe.cpp:
#include<iostream>
#include "Maybe.hpp"
using namespace std;
using namespace Functional_Maybe;
int main() {
Maybe<string> a{Maybe<string>::Just("hello") };
if(!isNothing(a)) cout << "yeih2 " << fromJust(a) << endl;
return 0;
}
Maybe.hpp
#pragma once
#include<stdexcept>
#include<iostream>
using namespace std;
namespace Functional_Maybe {
template <typename T>
class Maybe {
const T* value;
public:
Maybe(T *v) : value { v } {} //public for return in join
const static Maybe<T> nothing;
static Maybe<T> Just (const T &v) { cout << "c1" << endl; return Maybe<T> { new T(v) }; }
T fromJust() const {
if (isNothing()) throw std::runtime_error("Tried to extract value from Nothing");
cout << "\nvalue not null: " << value << " " << *value << endl;
// ^ stops here
return *value;
}
bool isNothing() const { return value==nullptr; }
~Maybe() { if (value != nullptr) delete value; }
};
template <typename T>
bool isNothing(Maybe<T> val) {
return val.isNothing();
}
template <typename T>
T fromJust(Maybe<T> val) {
return val.fromJust();
}
}
你class模板Maybe
拥有资源(动态分配T
),但不遵循Rule of Three:(隐式定义)复制和移动操作只做浅拷贝,这会导致 use-after-free 和 double-free 问题。您应该为 class 实施适当的复制和移动操作(构造函数和赋值运算符),或者使用 std::unique_ptr<const T>
作为 value
的类型,并删除您的手动析构函数(从而遵循首选零规则)。
旁注:您是否调查过 std::optional
(or, in pre-C++17 versions, boost::optional
)?他们似乎在做一些与您提议的 class 非常相似(甚至相同)的事情,您可能想改用它们(或者在您的 class 内部使用它们,如果这更适合您的话)。它们甚至可能更高效,在某些情况下使用小对象优化来避免动态内存分配。
我正在用 C++11 编写 Haskell Maybe Monad 的实现。
但是当我尝试测试代码时卡住了。当我使用伪构造函数 Just
构造一个类型的值,然后尝试使用函数 fromJust
对其进行评估时(应该只是 "unpack" 放置在 Maybe 中的值)程序停止并最终静默终止。
所以我尝试调试它;这是 testMaybe.cpp:
代码的输出c1
yeih2
value not null: 0xf16e70
我添加了几个打印语句来评估程序停止的位置,它似乎停止在我取消引用指向 return 值的指针的确切位置。 (我已经在代码中标注了。)
起初我认为 maybe 中的值可能在我想取消引用指针时被解构,据我所知,这将导致未定义的行为或终止。但是,我找不到发生这种情况的地方。
你能告诉我为什么会这样吗?
testMaybe.cpp:
#include<iostream>
#include "Maybe.hpp"
using namespace std;
using namespace Functional_Maybe;
int main() {
Maybe<string> a{Maybe<string>::Just("hello") };
if(!isNothing(a)) cout << "yeih2 " << fromJust(a) << endl;
return 0;
}
Maybe.hpp
#pragma once
#include<stdexcept>
#include<iostream>
using namespace std;
namespace Functional_Maybe {
template <typename T>
class Maybe {
const T* value;
public:
Maybe(T *v) : value { v } {} //public for return in join
const static Maybe<T> nothing;
static Maybe<T> Just (const T &v) { cout << "c1" << endl; return Maybe<T> { new T(v) }; }
T fromJust() const {
if (isNothing()) throw std::runtime_error("Tried to extract value from Nothing");
cout << "\nvalue not null: " << value << " " << *value << endl;
// ^ stops here
return *value;
}
bool isNothing() const { return value==nullptr; }
~Maybe() { if (value != nullptr) delete value; }
};
template <typename T>
bool isNothing(Maybe<T> val) {
return val.isNothing();
}
template <typename T>
T fromJust(Maybe<T> val) {
return val.fromJust();
}
}
你class模板Maybe
拥有资源(动态分配T
),但不遵循Rule of Three:(隐式定义)复制和移动操作只做浅拷贝,这会导致 use-after-free 和 double-free 问题。您应该为 class 实施适当的复制和移动操作(构造函数和赋值运算符),或者使用 std::unique_ptr<const T>
作为 value
的类型,并删除您的手动析构函数(从而遵循首选零规则)。
旁注:您是否调查过 std::optional
(or, in pre-C++17 versions, boost::optional
)?他们似乎在做一些与您提议的 class 非常相似(甚至相同)的事情,您可能想改用它们(或者在您的 class 内部使用它们,如果这更适合您的话)。它们甚至可能更高效,在某些情况下使用小对象优化来避免动态内存分配。