В настоящее время у меня есть структура, которая объявляет конструктор копирования и деструктор и сохраняет счетчик ссылок на объект pimpl. Это позволяет мне передавать эту структуру по значению. Мне нужно реорганизовать его, потому что я хочу, чтобы он имел интерфейс POD, потому что это часть библиотеки, которую теперь нужно использовать из кода, который использует более старую версию C ++.
Из-за этого мне нужно удалить и конструктор копирования, и дескриптор. Я не могу понять, как я могу сохранить этот замечательный «механизм передачи по значению», механизм множественного владения после того, как я его удалил. Общие указатели не являются опцией, потому что структура используется в качестве параметра для метода других классов, которые также должны рассматриваться как POD с точки зрения пользователя библиотеки.
struct Foo {
Foo(const Foo&);
const Foo& operator=(const Foo&);
~ Foo();
private:
void* pimpl;
};
struct MainLibrary {
void DoSomething(Foo param);
}
Код пользователя теперь выглядит так:
MainLibrary ml;
{
Foo a;
ml.doSomething(a);
}
в этот момент переменная может долго храниться в основной библиотеке. Для эффективности внутренности Foo нельзя копировать глубоко каждый раз, поэтому реализация pimpl сохраняет счетчик ссылок, который увеличивается каждый раз, когда копируется экземпляр Foo, уменьшается каждый раз, когда экземпляр Foo уничтожается.
Слишком много для комментария … что-то вроде ниже. Клиент включает foo03.h и их использование должно остаться без изменений. Ваша реализация C ++ 11 вызывается через слой «C». Вы можете найти множество примеров, если вы ищете «разоблачение кода C ++ для C» или подобное …
foo03.h:
extern "C"{
void* foo_constructor();
void* foo_constructor2(void* rhs);
void foo_assign(void* lhs, void* rhs);
void foo_destructor(void* p_this);
}
struct Foo {
Foo() { p_ = foo_constructor(); }
Foo(const Foo& rhs) { p_ = foo_constructor2(rhs.p_); }
const Foo& operator=(const Foo& rhs) { foo_assign(p_, rhs.p_); return *this; }
~Foo() { foo_destructor(p_); }
private:
void* p_;
};
foo11.h:
// up to you whether you call this Foo (relying on mangling differences to avoid conflicts when
// linking with C++03 objects), FooImpl, put it in a namespace ala Impl::Foo etc..
struct FooImpl {
FooImpl() { ... }
FooImpl(const FooImpl&) { ... }
const FooImpl& operator=(const FooImpl& rhs) { ... }
~FooImpl() { ... }
};
extern "C"{
void* foo_constructor() { return new FooImpl(); }
void* foo_constructor2(void* rhs) { return new FooImpl(*(FooImpl*)rhs); }
void foo_assign(void* lhs, void* rhs) { *(FooImpl*)lhs = *(FooImpl*)rhs; }
void foo_destructor(void* p_this) { delete (FooImpl*)p_this; }
}