2014-11-07 5 views
1

Я сделал привязки к C api (движок физики пули) с помощью cgo, некоторые функции используют указатели данных. Идея состоит в том, что я могу прикрепить указатель к объекту и получить его позже, когда физический движок вызывает обратный вызов. Моя проблема в том, что когда я получаю значение обратно, он меняется, и я этого не делал. Похоже, что исходный код явно не меняет значение.Значение указателя cgo изменено

CollisionObject: source, header, The go codes that interracts with that class

вот как я отправить значения, реконверсии к * междунар и междунар прекрасно, правильные номера печатаются:

num := x*amounty*amountz + y*amountz + z + 1 
ptr := unsafe.Pointer(&num) 
fmt.Printf("created %v %v\n", ptr, *(*int)(ptr)) 
rb := sphere.RigidBody(ptr, 1) 

Но когда Я получаю это назад от raytest значение изменилось:

ptr := hit.GetUserPointer() 
log.Printf("we got back: %v %v", ptr, *(*int)(ptr)) 

Значение указателя само по себе не изменилось, я могу посмотреть вверх и увидеть, что указатель указывает на это местоположение, но значение, указывающее на это, отличается.

Теперь мне интересно, может быть, пойти не очистит значение (сбор мусора), так как он больше не будет использоваться и заменяет это место памяти чем-то другим.

пример вывод (со значениями барахла удалены):

created: 0xc2080006e0 40 
2014/11/07 17:10:01 we got back: 0xc2080006e0 4921947622888946315 

ANY указатель (хех) ценятся :)

+0

Получает GC'ed Вам нужно сохранить этот указатель в Go, чтобы он этого не сделал. – JimB

+0

@JimB также, Go's GC разрешено перемещать указатели вокруг. Хранение указателей на стороне C абсолютно небезопасно. – LinearZoetrope

+0

@Jsor, технически верно, но это еще нет. Существует много кода, который передает указатели на cgo, потому что это лучшее, что у нас есть сейчас. Это должно быть лучше определено go1.5. (В этом случае, хотя для указателя нет веской причины, скопируйте значение в) – JimB

ответ

2

сборщик мусор Go не знает, о указателях, принадлежащих C или код C++, поэтому нет ничего, чтобы сохранить активную переменную num.

Вы можете обойти это, сохранив вторую копию указателя в переменной Go. Один из способов - использовать глобальную переменную с типом, например map[*C.some_c_type]*int или аналогичным, и хранить там &num. Не забудьте защитить карту с помощью мьютекса, чтобы все было правильно, если у вас есть одновременный доступ.

Чтобы не просочиться, вам необходимо вручную удалить &num с карты, если базовый код C больше не содержит ссылки на него. Если библиотека C предоставляет возможность устанавливать функцию уведомления об уничтожении при сохранении указателя пользователя, это будет легко: просто экспортируйте функцию Go в C и используйте ее как функцию уведомления. Если это не так, но привязка Go знает, когда указатель будет закончен (например, если переменная RigidBody всегда освобождается через API Go, вы можете сделать ее там.