std :: map, хранит указатель (на объект) по указателю (на некоторую связанную с объектом структуру).Какие типы использовать? - PullRequest
1 голос
/ 22 апреля 2011

Чтобы преодолеть невозможность предоставления библиотеке C обратного вызова функции-члена C ++, хотелось реализовать что-то вроде этого:

SomeObject* findSomeObjectByHandlePointer(datahandle *dh) { }..

с использованием карты, которая содержит адреса * datahandle в качестве индекса и адреса * SomeObject's в качестве значения.

Когда создается SomeObject, он создает группу дескрипторов данных, которые являются уникальными для объекта. Затем он передает указатель на * datahandle и статическую функцию обратного вызова в библиотеку C, затем библиотека C перезванивает и возвращает указатель на datahandle, который, в свою очередь, может быть связан с SomeObject.

Какие типы вы можете порекомендовать для хранения значений указателей на карте, кроме безопасных, но медленных <string, SomeObject*>?


Этот ответ говорит мне, чтобы я тоже не использовал auto_ptr.

Ответы [ 4 ]

4 голосов
/ 22 апреля 2011

Обычно C-подобные обратные вызовы принимают параметр void* user_data, который позволяет передавать все, что вы хотите:

void c_func(void (*fptr)(void*), void* user_data){
  // do some stuff
  fptr(user_data);
}

Теперь просто сделайте следующую статическую функцию-член:

class A{
public:
  static void c_callback(void* my_data){
    A* my_this = static_cast<A*>(my_data);
    // do stuff with my_this
  }
};

Редактировать: Согласно комментарию @ Martin, вам может не повезти со статической функцией-членом.Лучше использовать функцию extern "C": extern "C" void c_callback (void * my_data) {// то же, что и статический метод} И передать этот + ваш A экземпляр этому c_func:

int main(){
  A a;
  c_func(&A::c_callback,&a);
}

Или, если этот экземпляр A должен пережить текущую область действия, вам нужно каким-то образом сохранить указатель, выделенный в куче, где-нибудь и впоследствии удалить его вручную.A shared_ptr или лайки здесь не сработают, к сожалению.: (


Что касается вашей проблемы с сохранением указателя на карте, это не проблема, посмотрите этот небольшой пример на Ideone .

1 голос
/ 22 апреля 2011

Если у вас много операций чтения и записи меньше, вы можете использовать вектор как набор.Это очень часто, потому что lower_bound более эффективен, чем map и использует меньше места в памяти:

typedef std::pair<std::string,Your_pointer> your_type;
bool your_less_function( const your_type &a, const your_type &b )
{
  // your less function
  return ( a < b );
}
...
std::vector<your_type> ordered-vector;

Когда вы добавляете значения:

...
ordered-vector.push_back(value)
...
// Finally. The vector must be sorted before read.
std::sort( ordered-vector.begin(), ordered-vector.end(), your_less_function );

Когда запрашиваете данные:

std::vector<your_type>::iterator iter = std::lower_bound( ordered-vector.begin(), ordered-vector.end(), value, your_less_function );
if ( ( iter == ordered-vector.end() ) || your_less_function( *iter, value ) )
  // you did not find the value
else
  // iter contains the value
1 голос
/ 22 апреля 2011

Часто функции обратного вызова имеют дополнительный параметр типа void*, который можно использовать для передачи любых дополнительных данных, которые могут вам понадобиться. Поэтому, если вы хотите использовать функцию-член в качестве обратного вызова, вы передаете указатель на объект, приведенный к void*, а затем приводите его обратно и вызываете функцию-член в функции обратного вызова.

1 голос
/ 22 апреля 2011

Я думаю, этого будет достаточно. Это то, что мы используем:

class datahandle;
class SomeObject;

typedef std::map<datahandle*, SomeObject*> pointer_map;

pointer_map my_map;

SomeObject* findSomeObjectByHandlePointer( datahandle *dh) {
    pointer_map::const_iterator ff = my_map.find(dh);
    if (ff != my_map.end()) {
        return ii->second;
    }
    return NULL;
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...