Closed LaplaceSoda closed 2 months ago
I'm not seeing with with gfortran 12.3.0. I get:
{
"aaa": {
"bbb": 1,
"ccc": {
"ddd": 2
},
"eee": 3,
"fff": 0.45E+1
}
}
{
"ddd": 2
}
{
"aaa": {
"bbb": 1,
"ccc": {
"ddd": 2
},
"eee": 3,
"fff": 0.45E+1
}
}
I can try to test with gfortran 13 when I get a chance...
At first I thought using
call new_json%initialize(path_mode=2)
call new_json%add(value)
can solve the problem.
But apparently I am wrong, in this more complex main.f90
, the above problem arises again.
program main
use json_module
implicit none
type(json_file) :: json
logical :: found
integer :: i
call json%initialize(path_mode=2)
call json%load('test.json')
call test(json)
print *, 'json after test():'
call json%print()
call json%get('/aaa/eee', i, found=found)
print *, 'e=', i
call json%get('/aaa/ccc/ddd', i, found=found)
print *, 'd=', i
contains
subroutine test(json)
type(json_file) :: json
type(json_file) :: new_json
type(json_value), pointer :: value
logical :: found
print *, "test's json get from main:"
call json%print()
call json%get("/aaa/ccc", value, found)
call new_json%initialize(path_mode=2)
call new_json%add(value)
print *, "new_json before test01():"
call new_json%print()
call test01(new_json)
print *, "new_json after test01():"
call new_json%print()
print *, "json after test01():"
call json%print()
end subroutine test
subroutine test01(json)
type(json_file) :: json
integer :: d
print *, "test01's json get from test:"
call json%print()
call json%get('/ddd', d, found=found)
print *, 'd=', d
end subroutine test01
end program main
And here are the results:
test's json get from main:
{
"aaa": {
"bbb": 1,
"ccc": {
"ddd": 2
},
"eee": 3,
"fff": 0.45E+1
}
}
new_json before test01():
{
"ddd": 2
}
test01's json get from test:
{
"ddd": 2
}
d= 2
new_json after test01():
{
"ddd": 2
}
json after test01():
{
"aaa": {
"bbb": 1,
"ccc": {
"ddd": 2
},
"eee": 3,
"fff": 0.45E+1
}
}
json after test():
{
"aaa": {
"bbb": 1,
e= 0
d= 0
So what should I do to pass parts of the json to the subroutine safely without affecting the original json_file object?
My guess is that this issue is related to the destructor, but I don't know how to avoid it.
Tests found that after passing the json_file object (or a certain part) to the subfunction for processing,destroying the original object (automatically by finalizer) would also raise an exception, causing the program to exit.
The issue here is that you are extracting a pointer from one json_file, putting it into another json_file, which then gets destroyed when that variable goes out of scope. the two options you have when you do this are to make a deep copy of the pointer before putting it in the 2nd structure, or nullifying the pointer in the 2nd structure before it goes out of scope. I'll try to make an example...
Option 1:
subroutine test(json)
type(json_file) :: json
type(json_file) :: new_json
type(json_value), pointer :: value, value_clone
type(json_core) :: j
logical :: found
print *, "test's json get from main:"
call json%print()
call json%get("/aaa/ccc", value, found)
call j%clone(value, value_clone) ! make a deep copy of this, so we dont destroy part of the original structure when new_json goes out of scope
call new_json%initialize(path_mode=2)
call new_json%add(value_clone)
print *, "new_json before test01():"
call new_json%print()
call test01(new_json)
print *, "new_json after test01():"
call new_json%print()
print *, "json after test01():"
call json%print()
end subroutine test
Option 2:
subroutine test(json)
type(json_file) :: json
type(json_file) :: new_json
type(json_value), pointer :: value
logical :: found
print *, "test's json get from main:"
call json%print()
call json%get("/aaa/ccc", value, found)
call new_json%initialize(path_mode=2)
call new_json%add(value)
print *, "new_json before test01():"
call new_json%print()
call test01(new_json)
print *, "new_json after test01():"
call new_json%print()
call new_json%nullify() ! Nullify the pointer because its also in the original structure, we dont want this routine to destroy it.
print *, "json after test01():"
call json%print()
end subroutine test
The issue here is that you are extracting a pointer from one json_file, putting it into another json_file, which then gets destroyed when that variable goes out of scope.
Thanks a lot. This is the main reason! It is because of part of the pointer being destroyed in subroutine automatically that the original object can no longer be a normal object and then can no longer use get
function or be destroyed normally.
nullifying the pointer in the 2nd structure before it goes out of scope
This way seems more momery-less,so I tryed this way first. And the result shows that it works well! Thank you very much again!
But eventually I found that it seems that we still can't use json_file
constructor to new a new_object if we want keep the original json_file object normal (under gfortran 14.1.0-3). My guess is because the constructor will nullify the passed pointer, this part in original object is removed(?). I don't know if it truly affects
Yes, if you use the json_file(p)
constructor, it nullifies the input. if you don't want that, you can use call json_file%add(p)
which will leave it alone, but you have to careful since you now have an object that will destroy p
when it goes out of scope.
you have to careful since you now have an object that will destroy p when it goes out of scope
Yes, now I have learned always using nullify
the new object before return to protect the original pointer from being destroyed. Thank you very much.
By the way,it seems that nullify_pointer=.false.
don't improve the status while using add(value,destroy_original=.false.)
is easier and safer.
After creating an new object of json_file type from one json_file object, any remaining key-value pairs in origin json will be erased.
Environment
gfortran 13.2.0 (Built by MSYS2 project) fpm 0.10.0, alpha
Reproduction
Here is the
test.json
We try to get something from it in this
main.f90
and separate a portion (which could be used as an input for another function)The result shows that something in origin json_file object has been removed after a new object is created. And we can no longer get any things from it.![image](https://github.com/jacobwilliams/json-fortran/assets/59534681/45c1addf-cbb2-4e08-a046-d6f641dadf76)