我有以下代码.
#include <iostream>
int * foo()
{
int a = 5;
return &a;
}
int main()
{
int* p = foo();
std::cout << *p;
*p = 8;
std::cout << *p;
}
Run Code Online (Sandbox Code Playgroud)
而代码只是运行而没有运行时异常!
输出是 58
怎么会这样?本地变量的内存不能在其功能之外无法访问吗?
比较悬空指针是否合法?
int *p, *q;
{
int a;
p = &a;
}
{
int b;
q = &b;
}
std::cout << (p == q) << '\n';
Run Code Online (Sandbox Code Playgroud)
注意如何既p与q点有对象已经消失了.这合法吗?
我知道这是很常见的问题,但对我来说还是新的!
我不明白悬挂指针的概念,谷歌搜索,并编写测试方法找到一个.
我只是想知道这是一个悬垂的指针吗?无论我发现什么样的东西都回来了,我在这里尝试类似的东西!
谢谢!
void foo(const std::string name)
{
// will it be Dangling pointer?!, with comments/Answer
// it could be if in new_foo, I store name into Global.
// Why?! And what is safe then?
new_foo(name.c_str());
}
void new_foo(const char* name)
{
// print name or do something with name...
}
Run Code Online (Sandbox Code Playgroud) 这段代码有效吗?
const char* foo() {
return "Hello World";
}
Run Code Online (Sandbox Code Playgroud)
也就是说,从C函数返回"Hello World".
const char* str = foo();
Run Code Online (Sandbox Code Playgroud)
str是一个悬垂的指针吗?
PS:上面的函数是从一些实际代码中抽象出来的.我看到有人编写直接返回字符串文字的代码.
我正在为一个C库编写Python绑定,该库使用共享内存缓冲区来存储其内部状态.这些缓冲区的分配和释放是由Python本身在Python之外完成的,但我可以通过从Python中调用包装的构造函数/析构函数来间接控制何时发生这种情况.我想将一些缓冲区暴露给Python,以便我可以从它们中读取,并在某些情况下将值推送给它们.性能和内存使用是重要的问题,因此我希望尽可能避免复制数据.
我目前的方法是创建一个numpy数组,提供对ctypes指针的直接视图:
import numpy as np
import ctypes as C
libc = C.CDLL('libc.so.6')
class MyWrapper(object):
def __init__(self, n=10):
# buffer allocated by external library
addr = libc.malloc(C.sizeof(C.c_int) * n)
self._cbuf = (C.c_int * n).from_address(addr)
def __del__(self):
# buffer freed by external library
libc.free(C.addressof(self._cbuf))
self._cbuf = None
@property
def buffer(self):
return np.ctypeslib.as_array(self._cbuf)
Run Code Online (Sandbox Code Playgroud)
除了避免复制,这也意味着我可以使用numpy的索引和赋值语法,并将其直接传递给其他numpy函数:
wrap = MyWrapper()
buf = wrap.buffer # buf is now a writeable view of a C-allocated buffer
buf[:] = np.arange(10) # this is pretty cool!
buf[::2] += 10 …Run Code Online (Sandbox Code Playgroud) Clang 3.9非常重用临时使用的内存.
此代码是UB(简化代码):
template <class T>
class my_optional
{
public:
bool has{ false };
T value;
const T& get_or_default(const T& def)
{
return has ? value : def;
}
};
void use(const std::string& s)
{
// ...
}
int main()
{
my_optional<std::string> m;
// ...
const std::string& s = m.get_or_default("default value");
use(s); // s is dangling if default returned
}
Run Code Online (Sandbox Code Playgroud)
我们有大量类似上面的代码(my_optional只是一个简单的例子来说明它).
因为UB所有的clang编译器从3.9开始重用这个内存,而且它是合法的行为.
问题是:如何在编译时检测这种悬空引用,或者在运行时检测清理程序?没有clang消毒剂可以检测到它们.
UPD.请不要回答:"使用std::optional".仔细阅读:问题不是关于它.
UPD2.请不要回答:"你的代码设计很糟糕".仔细阅读:问题不是代码设计.
考虑std::string_view从返回a 的方法const std::string&或从空字符串返回的方法。令我惊讶的是,以这种方式编写方法会导致悬空的字符串视图:
const std::string& otherMethod();
std::string_view myMethod(bool bla) {
return bla ? otherMethod() : ""; // Dangling view!
}
Run Code Online (Sandbox Code Playgroud)
似乎编译器首先将std::string结果的临时副本otherMethod()放在堆栈上,然后返回此临时副本的视图,而不是仅返回引用的视图。首先,我想到了一个comipler错误,但是G ++和clang都这样做。
修复很容易:将其包装otherMethod为一个显式结构即可string_view解决此问题:
std::string_view myMethod(bool bla) {
return bla ? std::string_view(otherMethod()) : ""; // Works as intended!
}
Run Code Online (Sandbox Code Playgroud)
为什么会这样呢?为什么原始代码会在没有警告的情况下创建隐式副本?
std::vector将成员函数at()作为安全替代operator[],以便应用绑定检查并且不会创建悬空引用:
void foo(std::vector<int> const&x)
{
const auto&a=x[0]; // What if x.empty()? Undefined behavior!
const auto&a=x.at(0); // Throws exception if x.empty().
}
Run Code Online (Sandbox Code Playgroud)
但是,std::unique_ptr缺少相应的功能:
void foo(std::unique_ptr<int> const&x)
{
const auto&a=*x; // What if bool(x)==false? Undefined behavior!
}
Run Code Online (Sandbox Code Playgroud)
如果std::unique_ptr有这样一个安全的替代方案,那就好了,说成员ref()(和cref())永远不会返回一个悬空引用,而是抛出异常.可能的实施:
template<typename T>
typename add_lvalue_reference<T>::type
unique_ptr<T>::ref() const noexcept(false)
{
if(bool(*this)==false)
throw run_time_error("trying to de-refrence null unique_ptr");
return this->operator*();
}
Run Code Online (Sandbox Code Playgroud)
这个标准没有提供这种东西有什么好的理由吗?
我正在学习Stanley B. Lippman的C++ Primer第4版.在第12.4.1节中,当作者讨论构造函数初始值设定项时,他给出了这个例子:
class ConstRef {
public:
ConstRef(int ii);
private:
int i;
const int ci;
int &ri;
};
// OK: explicitly initialize reference and const members.
ConstRef::ConstRef(int ii): i(ii), ci(i), ri(ii) { }
Run Code Online (Sandbox Code Playgroud)
我怀疑这可能导致悬挂引用ri指向ii,这是暂时的.我对吗?
dangling-pointer ×10
c++ ×8
pointers ×3
c ×2
c++11 ×2
c++17 ×1
clang++ ×1
ctypes ×1
dereference ×1
numpy ×1
python ×1
reference ×1
string-view ×1
swift ×1
unique-ptr ×1