例如,在 Julia 会话结束之前使用 col0 col1 col2
0 0 1 -10.5
1 3 4 -7.5
2 6 7 -4.5
3 9 10 -1.5
4 12 13 1.5
5 15 16 4.5
6 18 19 7.5
7 21 22 10.5
返回的指针是否安全?在这种情况下,foo
和 foo
之间没有区别,对吗?
bar
foo(s::String="foo") = Base.unsafe_convert(Ptr{UInt8}, Base.cconvert(Ptr{UInt8}, s))
编辑:
我想添加更多背景信息。我正在尝试连接 C++ 库中的一些方法,该库具有默认为 C++ 字符串文字的默认参数值。派生指针用作“引用”(请参阅下面的链接)。在 C++ 中只使用文字似乎没问题,我想知道在 Julia 中这样做的最佳方法是什么。 (我认为 bar() = Base.unsafe_convert(Ptr{UInt8}, Base.cconvert(Ptr{UInt8}, "foo"))
不是一个好的解决方案,因为很难知道何时可以安全地对资源进行 GC。)
答案 0 :(得分:1)
从文档来看,答案似乎是一个相当明确的“否”。
首先,正如您可能知道的(并且确实可能从名称中猜到),Base.unsafe_convert
在这方面没有提供安全性,带有文档字符串警告
小心确保 Julia 对 x 的引用存在,只要此函数的结果将被使用
仅凭指针的存在肯定不会提供这一点。更糟糕的是,作为 Base.cconvert
注释
convert 和 cconvert 都不应将 Julia 对象转换为 Ptr。
将 Julia 对象转换为 Ptr
的推荐方法是什么?这似乎是 Base.pointer
,它在其文档中提供了更多有用的信息
help?> Base.pointer
pointer(array [, index])
Get the native address of an array or string, optionally at a given location index.
This function is "unsafe". Be careful to ensure that a Julia reference to array exists
as long as this pointer will be used. The GC.@preserve macro should be used to protect
the array argument from garbage collection within a given block of code.
Calling Ref(array[, index]) is generally preferable to this function as it guarantees
validity.
值得注意的是,
返回的指针julia> s = "some string"
"some string"
julia> Base.pointer(s)
Ptr{UInt8} @0x000000010d4b2838
julia> Base.unsafe_convert(Ptr{UInt8}, s)
Ptr{UInt8} @0x000000010d4b2838
julia> Base.unsafe_convert(Ptr{UInt8}, Base.cconvert(Ptr{UInt8}, s))
Ptr{UInt8} @0x000000010d4b2838
完全相同。
可以依次在 Base.GC.@preserve
文档字符串中找到更多有用的信息:
help?> Base.GC.@preserve
GC.@preserve x1 x2 ... xn expr
Mark the objects x1, x2, ... as being in use during the evaluation of the expression
expr. This is only required in unsafe code where expr implicitly uses memory or other
resources owned by one of the xs.
Implicit use of x covers any indirect use of resources logically owned by x which the
compiler cannot see. Some examples:
• Accessing memory of an object directly via a Ptr
• Passing a pointer to x to ccall
• Using resources of x which would be cleaned up in the finalizer.
@preserve should generally not have any performance impact in typical use cases where
it briefly extends object lifetime. In implementation, @preserve has effects such as
protecting dynamically allocated objects from garbage collection.
Examples
≡≡≡≡≡≡≡≡≡≡
When loading from a pointer with unsafe_load, the underlying object is implicitly
used, for example x is implicitly used by unsafe_load(p) in the following:
julia> let
x = Ref{Int}(101)
p = Base.unsafe_convert(Ptr{Int}, x)
GC.@preserve x unsafe_load(p)
end
101
When passing pointers to ccall, the pointed-to object is implicitly used and should be
preserved. (Note however that you should normally just pass x directly to ccall which
counts as an explicit use.)
julia> let
x = "Hello"
p = pointer(x)
Int(GC.@preserve x @ccall strlen(p::Cstring)::Csize_t)
# Preferred alternative
Int(@ccall strlen(x::Cstring)::Csize_t)
end
5
所以,一些带回家的点
Base.pointer(s)
返回的指向字符串的指针是安全的,当且仅当 (a) 后面的代码中存在对该字符串 s
的 Julia 引用或 (b) 您使用过 Base.GC.@preserve
Base.unsafe_convert(Ptr{UInt8}, Base.cconvert(Ptr{UInt8}, s))
返回的指针似乎与 Base.pointer
返回的指针具有相同的警告,但额外增加了一个神秘而不祥的警告。String
vs Array
vs 等等)很重要。答案 1 :(得分:0)
垃圾收集器可以使您的函数返回的引用无效,如果它们被垃圾收集器重新定位然后被引用。所以不要那样做。如果必须,您可以将代码包装在 GC.@preserve
宏中以将它们标记为不可重定位。注意我在使用不透明的 C 编译库时遇到过一些奇怪的情况,即使那样你也会使 Julia 崩溃,所以如果可以,请避免这种引用。宏就是这样完成的,见https://docs.julialang.org/en/v1/base/base/#Base.GC.@preserve:
GC.@preserve x y begin
x = foo()
y = bar()
@show x
# do stuff that might fire off the garbage collector ...
@show x
end
即使重新定位字符串“foo”本身也可以毫无顾虑地被引用,因为 Julia 总是知道任何给定的字符串 literal 在哪里。