pimpl и неименованное пространство
От: B0FEE664  
Дата: 06.11.15 12:17
Оценка:
Хочу сделать так:
// file: a.hpp

namespace {
class A_impl;
}

class A
{
  .....
  void f();
  private:
    A_impl* m_pimpl;
};


// file: a_impl1.cpp
#ifdef ...

namespace {
class A_impl
{
   // ...
};
}// namespace

void A::f()
{
  m_pimpl->f();
}


// file: a_impl2.cpp
#ifdef ...

namespace {
class A_impl
{
   // ...
};
}// namespace


void A::f()
{
  m_pimpl->f();
}


Есть подводные камни у такого решения?
И каждый день — без права на ошибку...
Отредактировано 09.11.2015 12:38 B0FEE664 . Предыдущая версия .
Re: VS bug: new int(1,2,"wtf")
От: Constructor  
Дата: 06.11.15 17:44
Оценка:
Здравствуйте, B0FEE664, Вы писали:

BFE>Есть подводные камни у такого решения?


Пробовали ли Вы скомпилировать это решение?
Re[2]: VS bug: new int(1,2,"wtf")
От: B0FEE664  
Дата: 06.11.15 18:38
Оценка:
Здравствуйте, Constructor, Вы писали:

BFE>>Есть подводные камни у такого решения?

C>Пробовали ли Вы скомпилировать это решение?

Да, конечно. Но может надо пояснить, что компиляция того или иного *.cpp определяется с помощью define'а. Меня интересует насколько безопасно помещать namespace { class A_impl; } в хедере.
И каждый день — без права на ошибку...
Re[3]: VS bug: new int(1,2,"wtf")
От: Constructor  
Дата: 09.11.15 12:19
Оценка:
Здравствуйте, B0FEE664, Вы писали:

BFE>Здравствуйте, Constructor, Вы писали:


BFE>>>Есть подводные камни у такого решения?

C>>Пробовали ли Вы скомпилировать это решение?

BFE>Да, конечно.


В таком случае Вы пользуетесь компилятором, который не соответствует стандарту. Каждое безымянное пространство имен уникально, поэтому подобный код компилироваться не должен (класс A [ A_impl в вашем случае] так и останется неполным типом, поскольку его "определение" — это всего лишь объявление другого класса с таким же именем в другом пространстве имен):

namespace
{
    class A;
}

namespace
{
    class B
    {
        A a;
    };
}

namespace
{
    class A
    {
    };
}

int main()
{
}
Re[4]: VS bug: new int(1,2,"wtf")
От: B0FEE664  
Дата: 09.11.15 12:37
Оценка:
Здравствуйте, Constructor, Вы писали:

C>В таком случае Вы пользуетесь компилятором, который не соответствует стандарту. Каждое безымянное пространство имен уникально,

Оно ведь уникально для единицы трансляции, а не для каждого упоминания?

C>поэтому подобный код компилироваться не должен (класс A [ A_impl в вашем случае] так и останется неполным типом, поскольку его "определение" — это всего лишь объявление другого класса с таким же именем в другом пространстве имен):


Pimpl это указатель прежде всего, сейчас поправлю исходное сообщение.
вот, скомпилировалось:
namespace
{
    class A;
}

namespace
{
    class B
    {
        public:
        A* a;
    };
}

namespace
{
    class A
    {
    };
}

int main()
{
}
И каждый день — без права на ошибку...
Re[5]: pimpl и неименованное пространство
От: Constructor  
Дата: 09.11.15 13:30
Оценка:
Здравствуйте, B0FEE664, Вы писали:

C>>В таком случае Вы пользуетесь компилятором, который не соответствует стандарту. Каждое безымянное пространство имен уникально,

BFE>Оно ведь уникально для единицы трансляции, а не для каждого упоминания?

Да, прошу прощения, перепутал.

C>>поэтому подобный код компилироваться не должен (класс A [ A_impl в вашем случае] так и останется неполным типом, поскольку его "определение" — это всего лишь объявление другого класса с таким же именем в другом пространстве имен):


BFE>Pimpl это указатель прежде всего, сейчас поправлю исходное сообщение.


Да, у Вас все правильно, вроде бы.
Но вместо

namespace {
class A_impl;
}

class A
{
  .....
  void f();
  private:
    A_impl* m_pimpl;
};


можно просто написать

class A
{
  .....
  void f();
  private:
    class A_impl* m_pimpl;
};
Re[5]: VS bug: new int(1,2,"wtf")
От: tdiff  
Дата: 09.11.15 14:16
Оценка: 1 (1) +1
Здравствуйте, B0FEE664, Вы писали:

BFE>Оно ведь уникально для единицы трансляции, а не для каждого упоминания?


Ок, а это не нарушает ODR?
В TU пользователя класса A и в TU a_impl1.cpp будут разные определения класса A.
Re[6]: VS bug: new int(1,2,"wtf")
От: B0FEE664  
Дата: 09.11.15 19:48
Оценка:
Здравствуйте, tdiff, Вы писали:

BFE>>Оно ведь уникально для единицы трансляции, а не для каждого упоминания?

T>Ок, а это не нарушает ODR?
T>В TU пользователя класса A и в TU a_impl1.cpp будут разные определения класса A.

И они будут лежать в разных namespace'ах, насколько я понимаю.
И каждый день — без права на ошибку...
Re[6]: VS bug: new int(1,2,"wtf")
От: enji  
Дата: 10.11.15 05:42
Оценка:
Здравствуйте, tdiff, Вы писали:

T>Ок, а это не нарушает ODR?

T>В TU пользователя класса A и в TU a_impl1.cpp будут разные определения класса A.

Нарушает по идее, но пользователь то видит только указатель. Имхо, врядли будут проблемы. Хотя конечно на кой так делать — это уже вопрос к ТС
Re[7]: VS bug: new int(1,2,"wtf")
От: uzhas Ниоткуда  
Дата: 10.11.15 07:22
Оценка: 8 (1) +1
Здравствуйте, B0FEE664, Вы писали:

T>>В TU пользователя класса A и в TU a_impl1.cpp будут разные определения класса A.


BFE>И они будут лежать в разных namespace'ах, насколько я понимаю.


класс A будет лежать в глобальном неймспейсе, но в TU пользователя класса A будет одно определение класса, а в a_impl1.cpp будет второе. как следствие — UB
если ты ограничишь использование класса A таким образом, что a.hpp будет инклюдиться только в в один cpp (например, a_impl1.cpp), то нарушения ODR уже не будет

вообще, есть замечательная рекомендация — избегайте анонимных неймспейсов в .hpp
Re[7]: VS bug: new int(1,2,"wtf")
От: uzhas Ниоткуда  
Дата: 10.11.15 07:27
Оценка:
Здравствуйте, enji, Вы писали:

E>Нарушает по идее, но пользователь то видит только указатель. Имхо, врядли будут проблемы.

компиляторы сейчас более агрессивно себя ведут и используют UB, как уважительную причину для своих фейлов оптимизации
Re: pimpl и неименованное пространство
От: sokel Россия  
Дата: 10.11.15 10:56
Оценка:
Здравствуйте, B0FEE664, Вы писали:

BFE>Хочу сделать так: ...


А наследование не устроит?

// .h
class A {
    struct Impl;
public:
    ...
    void foo() const;
private:
    Impl* impl_;
};

// .cpp
namespace {
    struct AImpl {
        void foo() const {}
    };
}
struct A::Impl : public AImpl {};
...
void A::foo() const {
    impl_->foo();
}


Ну или голый void*, если конструкторы суровые и не лень касты писать:
// .h
class A {
public:
    ...
    void foo() const;
private:
    void* impl_;
};

// .cpp
namespace {
    struct AImpl {
        void foo() const {}
    };
}
...
void A::foo() const {
    static_cast<const AImpl*>(impl_)->foo();
}
Re[2]: pimpl и неименованное пространство
От: sokel Россия  
Дата: 10.11.15 11:11
Оценка:
Здравствуйте, sokel, Вы писали:

S>Ну или голый void*, если конструкторы суровые и не лень касты писать

А для удобства можно в том же unnamed namespace касты подсократить:

namespace {
    struct AImpl { void foo() const {} };
    AImpl* get(void* p) { return static_cast<AImpl*>(p); }
}

A::A() : impl_(new AImpl) {}
A::~A() { delete get(impl_); }
void A::foo() const { get(impl_)->foo(); }
Re: pimpl и неименованное пространство
От: _Artem_ Россия  
Дата: 10.11.15 12:30
Оценка:
Здравствуйте, B0FEE664, Вы писали:

BFE>Хочу сделать так:

...
BFE>Есть подводные камни у такого решения?

А какой в этом смысл? Почему не сделать так?
// myclass.h

class MyClass
{
public:
    MyClass();

    int get_data() const;

private:
    class MyClassImpl * impl;
};

// myclass.cpp

class MyClassImpl
{
    MyClassImpl()
        : data(10)

    int get_data() const
    {
        return data;
    }

private:
    int data;
};

MyClass::MyClass()
    : impl(new MyClassImpl)
{
}

int MyClass::get_data() const
{
    return impl->get_data();
}
Re[2]: pimpl и неименованное пространство
От: uzhas Ниоткуда  
Дата: 10.11.15 12:52
Оценка: +1
Здравствуйте, _Artem_, Вы писали:

_A_>А какой в этом смысл? Почему не сделать так?


вот здесь можно посмотреть как сделать неглючный pimpl : http://rsdn.ru/forum/cpp.applied/6232610.flat
Автор: Kingofastellarwar
Дата: 02.11.15
Re[2]: pimpl и неименованное пространство
От: sokel Россия  
Дата: 10.11.15 20:33
Оценка:
Здравствуйте, _Artem_, Вы писали:

_A_>А какой в этом смысл? Почему не сделать так?


Внутренняя линковка, помещение реализации в unnamed namespace полностью изолирует её от других единиц трансляции.
Re[8]: VS bug: new int(1,2,"wtf")
От: B0FEE664  
Дата: 13.11.15 17:37
Оценка:
Здравствуйте, uzhas, Вы писали:

T>>>В TU пользователя класса A и в TU a_impl1.cpp будут разные определения класса A.

BFE>>И они будут лежать в разных namespace'ах, насколько я понимаю.
U>класс A будет лежать в глобальном неймспейсе, но в TU пользователя класса A будет одно определение класса, а в a_impl1.cpp будет второе. как следствие — UB

Спасибо. Не зря я сомневался.
И каждый день — без права на ошибку...
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.