LINUX.ORG.RU

forward declaration возможен?

 ,


0

2

Приветствую!

В продолжении темы ) Как обратиться к std::shared_ptr<void> ???

Хотелось бы из boost сделать forward declaration для boost::property_tree::ptree в классе по типу

class CJSON
{
private:
    boost::property_tree::ptree  pt;

public:
    CJSON(const char * msg, const int lmsg);
};

чтобы не всплывало ничего через хедеры в других местах.

Возможно такое??? Вариант моего нерабочего тупизма (

namespace boost {
    namespace property_tree {
        class basic_ptree;
        typedef basic_ptree<std::string, std::string> ptree;
    }
}

★★★

Можно сделать указатель на задекларированный тип:

struct A;
A *pa;

но уже работа с этим указателем (обращение к полям A), а тем более создание экземпляра A требует таки что бы A был определен полностью.

Поставьте себя на место компилятора - пойди туда не знаю куда или выдели память под то не знаю что - Вы бы так смогли?;-)

AntonI ★★★★★
()

Приблизительно так

В cjson.hpp:

#include <boost/property_tree/ptree_fwd.hpp>
#include <memory>

class CJSON
{
public:
    CJSON();
    ~CJSON();

private:
    std::unique_ptr<boost::property_tree::ptree> pt;
};

В cjson.cpp:

#include "cjson.hpp"
#include <boost/property_tree/ptree.hpp>

CJSON::CJSON() = default;
CJSON::~CJSON() = default;

Или еще в pimpl запихнуть можно. Тогда boost совсем «протекать» не будет.

PRN
()
Последнее исправление: PRN (всего исправлений: 4)

typedef basic_ptree<std::string, std::string> ptree;

Тут проявляется твой большоё пробел в понимании внутреннего устройства плюсов. Если в классе есть какое-то поле, то всем пользователям класса дожен быть известен его размер — чтобы было понятно, сколько места выделять под объект класса на стэке. Если у поля тип T* или T&, то размер поля — это размер указателя, и в таких случаях часто можно использовать forward declaration (естественно, для этого ещё нужно, чтобы никакие инлайн-методы не требовали каких-то ещё знаний о T, в том числе автоматические конструкторы и особенно деструкторы).

Edit: а в тех местах, когда можно обойтись без знания размера объекта CJSON, можно и нужно форвард-декларировать сам class CJSON вместо инклуда.

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

annulen ★★★★★
()
Последнее исправление: annulen (всего исправлений: 1)
Ответ на: комментарий от annulen

) это объявление в бусте, я только попытался повторить похожее на ptree_fwd.hpp

можно и нужно форвард-декларировать сам class CJSON вместо инклуда

ну т.е. в хедере пишу только class CJSON;, а в реализации уже все описываю? типа такого

hpp
class CJSON;


cpp
#include <boost/property_tree/ptree.hpp>
#include <boost/property_tree/json_parser.hpp>

#include "DownloaderJSON.hpp"

class CJSON
{
private:
    boost::property_tree::ptree pt;

public:
    CJSON(const char * msg, const int lmsg)
    {
        std::stringstream ss;
        ss.write(msg, lmsg);

        boost::property_tree::read_json(ss, pt);
    }
};

пробую такой вариант использовать и получаю ошибку

In file included from /usr/include/c++/8/memory:80,
                 from /usr/include/c++/8/thread:39,
                 from Downloader.cpp:5:
/usr/include/c++/8/bits/unique_ptr.h: In instantiation of ‘typename std::_MakeUniq<_Tp>::__single_object std::make_unique(_Args&& ...) [with _Tp = CJSON; _Args = {char*&, const int&}; typename std::_MakeUniq<_Tp>::__single_object = std::unique_ptr<CJSON, std::default_delete<CJSON> >]’:
Downloader.cpp:149:49:   required from here
/usr/include/c++/8/bits/unique_ptr.h:831:30: error: invalid use of incomplete type ‘class CJSON’
     { return unique_ptr<_Tp>(new _Tp(std::forward<_Args>(__args)...)); }
                              ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
In file included from Downloader.cpp:21:
DownloaderJSON.hpp:3:7: note: forward declaration of ‘class CJSON’
 class CJSON;
       ^~~~~
In file included from /usr/include/c++/8/memory:80,
                 from /usr/include/c++/8/thread:39,
                 from Downloader.cpp:5:
/usr/include/c++/8/bits/unique_ptr.h: In instantiation of ‘void std::default_delete<_Tp>::operator()(_Tp*) const [with _Tp = CJSON]’:
/usr/include/c++/8/bits/unique_ptr.h:274:17:   required from ‘std::unique_ptr<_Tp, _Dp>::~unique_ptr() [with _Tp = CJSON; _Dp = std::default_delete<CJSON>]’
Downloader.cpp:149:49:   required from here
/usr/include/c++/8/bits/unique_ptr.h:79:16: error: invalid application of ‘sizeof’ to incomplete type ‘CJSON’
  static_assert(sizeof(_Tp)>0,

или такую в зависимости от того как указатель инициализировать

Downloader.cpp:150:36: error: invalid use of incomplete type ‘class CJSON’
  auto pjson = new CJSON(msg, msgLen);
                                    ^
In file included from Downloader.cpp:21:
DownloaderJSON.hpp:3:7: note: forward declaration of ‘class CJSON’
 class CJSON;

wolverin ★★★
() автор топика
Последнее исправление: wolverin (всего исправлений: 1)
Ответ на: комментарий от PRN

хе хе, а в этом варианте, который сам изначально написал если при использовании auto pjson = new CJSON(msg, msgLen); ошибки компиляции нет, то при auto json = std::make_unique<CJSON>(msg, msgLen); получаю

In file included from /usr/include/c++/8/memory:80,
                 from /usr/include/c++/8/thread:39,
                 from Downloader.cpp:5:
/usr/include/c++/8/bits/unique_ptr.h: In instantiation of ‘void std::default_delete<_Tp>::operator()(_Tp*) const [with _Tp = boost::property_tree::basic_ptree<std::__cxx11::basic_string<char>, std::__cxx11::basic_string<char> >]’:
/usr/include/c++/8/bits/unique_ptr.h:274:17:   required from ‘std::unique_ptr<_Tp, _Dp>::~unique_ptr() [with _Tp = boost::property_tree::basic_ptree<std::__cxx11::basic_string<char>, std::__cxx11::basic_string<char> >; _Dp = std::default_delete<boost::property_tree::basic_ptree<std::__cxx11::basic_string<char>, std::__cxx11::basic_string<char> > >]’
DownloaderJSON.hpp:5:7:   required from ‘void std::default_delete<_Tp>::operator()(_Tp*) const [with _Tp = CJSON]’
/usr/include/c++/8/bits/unique_ptr.h:274:17:   required from ‘std::unique_ptr<_Tp, _Dp>::~unique_ptr() [with _Tp = CJSON; _Dp = std::default_delete<CJSON>]’
Downloader.cpp:149:49:   required from here
/usr/include/c++/8/bits/unique_ptr.h:79:16: error: invalid application of ‘sizeof’ to incomplete type ‘boost::property_tree::basic_ptree<std::__cxx11::basic_string<char>, std::__cxx11::basic_string<char> >’
  static_assert(sizeof(_Tp)>0,
wolverin ★★★
() автор топика
Ответ на: комментарий от AntonI

Поставьте себя на место компилятора - пойди туда не знаю куда или выдели память под то не знаю что - Вы бы так смогли?;-)

Почему бы и нет? На этапе линковки уже вся информация будет. А до этого этапа можно и отложить вычисления размеров. Ну в теории, если свой линкер и тд.

vbr ★★★★
()
Ответ на: комментарий от vbr

Дык от этих размеров скажем зависят другие размеры - придётся по второму разу перекомпилировать. А если там кольцевые зависимости то оно вообще не соберётся.

AntonI ★★★★★
()
Ответ на: комментарий от wolverin

Учи матчасть, читай что такое пимпл идиома - https://en.cppreference.com/w/cpp/language/pimpl

// --------------------
// interface (widget.h)
struct widget
{
    // public members
private:
    struct impl; // forward declaration of the implementation class
    // One implementation example: see below for other design options and trade-offs
    std::experimental::propagate_const< // const-forwarding pointer wrapper
        std::unique_ptr<                // unique-ownership opaque pointer
            impl>> pImpl;               // to the forward-declared implementation class
};
 
// ---------------------------
// implementation (widget.cpp)
struct widget::impl
{
    // implementation details
};

И все хидера буста помещать только в cpp файле. Тогда ничего не «протечет».

PRN
()
Последнее исправление: PRN (всего исправлений: 1)
Ответ на: комментарий от wolverin

то при auto json = std::make_unique(msg, msgLen); получаю

Я «на глаз» код писал, но в данном случае, скорее всего, ты опять что-то сделал через ж*пу)). Код CJSON::~CJSON() = default; в cpp был не для красоты XD

PRN
()
Последнее исправление: PRN (всего исправлений: 2)
Ответ на: комментарий от PRN

наличие деструктора никак не отменяет ошибку

/usr/include/c++/8/bits/unique_ptr.h:79:16: error: invalid application of ‘sizeof’ to incomplete type ‘boost::property_tree::basic_ptree<std::__cxx11::basic_string<char>, std::__cxx11::basic_string<char> >’
  static_assert(sizeof(_Tp)>0,
wolverin ★★★
() автор топика
Ответ на: комментарий от wolverin

хз, не работает так тоже

hpp
class CJSON
{
private:
    struct impl;
    std::unique_ptr<impl> pimpl;

public:
    CJSON(const char *, const int);
    ~CJSON() {}
};

cpp
#include <boost/property_tree/ptree.hpp>
#include <boost/property_tree/json_parser.hpp>

#include "DownloaderJSON.hpp"

struct CJSON::impl
{
    boost::property_tree::ptree pt;
};

CJSON::CJSON(const char * msg, const int lmsg)
    : pimpl(std::make_unique<impl>())
{
    std::stringstream ss;
    ss.write(msg, lmsg);
}
...

на объявление auto json = std::make_unique<CJSON>(msg, msgLen) все та же ошибка размера типа

/usr/include/c++/8/bits/unique_ptr.h: In instantiation of ‘void std::default_delete<_Tp>::operator()(_Tp*) const [with _Tp = CJSON::impl]’:
/usr/include/c++/8/bits/unique_ptr.h:274:17:   required from ‘std::unique_ptr<_Tp, _Dp>::~unique_ptr() [with _Tp = CJSON::impl; _Dp = std::default_delete<CJSON::impl>]’
DownloaderJSON.hpp:15:14:   required from here
/usr/include/c++/8/bits/unique_ptr.h:79:16: error: invalid application of ‘sizeof’ to incomplete type ‘CJSON::impl’
  static_assert(sizeof(_Tp)>0,                ^~~~~~~~~~~

wolverin ★★★
() автор топика
Последнее исправление: wolverin (всего исправлений: 1)
Ответ на: комментарий от wolverin

Пустой конструктор и деструктор, даже необъявленный конструктор и деструктор, делают очень много (грязного) дела. Это огромный плюс и огромный минус с++.

anonymous
()
Ответ на: комментарий от wolverin

LOL. Я же тебе латинскими буквами по-русски написал:

Код CJSON::~CJSON() = default; в CPP был не для красоты

Возможно, неоднозначно получилось))

PRN
()
Последнее исправление: PRN (всего исправлений: 1)
Ответ на: комментарий от wolverin

получается форвардится не условно базовый класс, а еще один промежуточный

Все верно. Только ещё все вызовы надо в этот класс прокидывать. И в CPP файле их писать.

PRN
()
Последнее исправление: PRN (всего исправлений: 1)
Ответ на: комментарий от PRN

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

…типа при выделении памяти на куче вообще нигде не отслеживается ее освобождение

wolverin ★★★
() автор топика
Последнее исправление: wolverin (всего исправлений: 2)
Ответ на: комментарий от wolverin

типа при выделении памяти на куче вообще нигде не отслеживается ее освобождение

Естественно. Вызов правильного деструктора — это забота кода, удаляющего объект. Добро пожаловать в С++.

annulen ★★★★★
()