LINUX.ORG.RU

Зачем нужен forward declaration в C++?

 ,


0

3

Не холивара ради, сравнение кода Swift и C++:

class Object {

	let inventory = Inventory()

}

class Inventory {

	var items = [Object]()

}

class Human: Object {}

class Sandals: Object {}

class Socks: Object {}

let human = Human()
human.inventory.items.append(Socks())
human.inventory.items.append(Sandals())

print("Items count: \(human.inventory.items.count)")

Собираем, запускаем:

swiftc includeEachOther.swift -o includeTest && ./includeTest 
Items count: 2

C++:

#include <vector>
#include <iostream>

using namespace std;

class Object {

public:

	Inventory *inventory;

};

class Inventory {

public:

	vector<Object *> items;

};

class Human: public Object {};

class Sandals: public Object {};

class Socks: public Object {};

int main() {

	auto human = new Human();

	human->inventory = new Inventory();
	
	human->inventory->items.push_back(new Sandals());
	human->inventory->items.push_back(new Socks());	

	cout << "Items count: " << human->inventory->items.size() << endl;

	return 0;

};

Собираем, запускаем:

 g++ -std=c++11 includeEachOther.cpp -o includeTest && ./includeTest

includeEachOther.cpp:10:2: error: unknown type name 'Inventory'
        Inventory *inventory;
        ^

Если добавить forward declaration - class Inventory в .cpp, то все заработает. Я не понимаю почему в C++ нужно это в 2017 году, кто-нибудь может объяснить?

Я не понимаю почему в C++ нужно это в 2017 году

потому что не знаешь ничего о C++, иди читай Страуструпа или смирись и прогай для веба

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

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

anonymous
()

Я не понимаю почему в C++ нужно это в 2017 году, кто-нибудь может объяснить?

в С++ однопроходный компилятор.

drsm ★★
()

Синтаксис такой, не хотите форвард декларации - делайте полное объявление как в C

#include <vector>
#include <iostream>

using namespace std;

class Object {

public:

        class Inventory *inventory;

};

class Inventory {

public:

        vector<Object *> items;

};

class Human: public Object {};

class Sandals: public Object {};

class Socks: public Object {};

int main() {

        auto human = new Human();

        human->inventory = new Inventory();

        human->inventory->items.push_back(new Sandals());
        human->inventory->items.push_back(new Socks());

        cout << "Items count: " << human->inventory->items.size() << endl;

        return 0;

};

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

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

Тут вроде только про неполное объявление класса. Но даже если взять функции - все равно непонятно что мешает вызвать объявленную далее функцию. Методы всё равно так умеют.

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

А если у тебя только хидер и бинарная либа? Представляешь, на сколько увеличится время компиляции, если символы искать везде.

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

Ну типа философия C - сначала объявляем, только потом пользуемся. Правда, не особо сильно ее держатся...

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

Представляешь, на сколько увеличится время компиляции, если символы искать везде

Имхо, не поменяется. Так и так работаем в рамках единицы трансляции. Просто на момент вызова не будет информации как его делать, придется потом вернуться. Для крестов - незначительное усложнение.

anonymous
()

Я не понимаю почему в C++ нужно это в 2017 году, кто-нибудь может объяснить?

Потому что C++ делают комитетские мудаки. C++17 тому порукой.

new Inventory();

А за использование ключевого слова «new» в современных плюсах нужно убивать.

За «vector<Object *>» и «....push_back(new ...)» — особенно мучительно.

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

оно изначально было designed for one-pass compilation. понятно что сейчас многопроходные везде компиляторы и это не актуально уже.

но менять это никто не будет, обратная совместимость дороже.

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

Даже в C есть ссылки вперед, в C++ их еще больше.

И вообще, язык проектируют под однопроходную компиляцию чтобы компилятор был простой и быстрый. Это прямо в точку про C++.

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

комитетские мудаки

Посмотрел бы я, во что ты превратишься, если придется работать в их условиях и выдавать их результат... Хотя, если тебе 15, то всё норм.

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

сходи в at&t расскажи, что они все сделали неправильно.

Они догадываются. Но дело не в этом, а в том что аргументы в этом треде приводятся несостоятельные.

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

А что нужно использовать в современных плюсах?

Зависит от того что нужно. Есть emplace, есть умные указатели (3 штуки)...

Страсть к разлапистым иерархиям и выпендрёжу с указателями очень быстро проходит: после первого же патологоанатомического сеанса с безвременно откинувшимся проектом.

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

Я вообще все в shared_ptr оборачиваю

Угу. Как будто это гарантия... ШаредПтр весел и задорен, особенно если забыть что это тупая RAII-обёртка без единой капли «волшебного порошка» и какой-либо поддержки в языковом рантайме.

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

Знаешь я не часто вижу что программы на iOS или OSX падали, или страдали утечками, там везде RC и shared_ptr с weak_ptr. Никто не говорит что это гарантия.

orkshaman
() автор топика

Потому что C++ пытается здесь косить под C, который расчитан на однопроходный компилятор. По факту это уже давно не так, но никто не может это починить. Хрень с хидерами оттуда же растёт.

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

ломать обратную совместимость они не собираются.

Бвахахахахах! Охохохохох! Уахахахахахахах!

То-то в C++11/14/17 фишки стали выпиливать.

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

Есть мнение что reference counting удел недалеких ;)

Есть мнение, что все кто хотел свалить с C++ — давно уже свалили.

Я обычно такие высеры не читаю, но специально ради тебя прошёл по ссылке. Дочитал только до

Each time a smart pointer is passed along, there's implicit overhead.

Извини, но аффтар не понимает как работает C++. А своё непонимание пытается скрыть за «седыми яйцами» и апломбом.

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

То-то в C++11/14/17 фишки стали выпиливать.

Выпиливают в основном всякую бессмыслицу.

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

Извини, но аффтар не понимает как работает C++. А своё непонимание пытается скрыть за «седыми яйцами» и апломбом.

На самом деле это ты чукча писатель, а не читатель. А аффтар на этот счёт пишет всё правильно.

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

Each time a smart pointer is passed along, there's implicit overhead.

Извини, но аффтар не понимает как работает C++. А своё непонимание пытается скрыть за «седыми яйцами» и апломбом.

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

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

Ну да, всего лишь при каждом разыменовании кэш процессора слетает в задницу.

Согласись, когда тебе действительно важно моральное состояние кешей процессора, произвольными указателями не пользуются, тем более умными.

Тебе какой-нибудь std::string натворит зла намного больше, да и любой (окромя std::array) стандартный контейнер в тёплых чувствах к кешу уличён не был.

Macil ★★★★★
()

legacy

разработчики компиляторов C++ и так мучаются с каждым новым стандартом

вообще компиляторы C++, в силу убогости и жирности языка - емнип, самые сложные из компиляторов, на текущий момент

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

Согласись, когда тебе действительно важно моральное состояние кешей процессора, произвольными указателями не пользуются, тем более умными.

Учитывая, что указатели являются основным средством построения структур данных, выбора тут нет.

Тебе какой-нибудь std::string натворит зла намного больше, да и любой (окромя std::array) стандартный контейнер в тёплых чувствах к кешу уличён не был.

Я намекал на атомарность, которая необходима для подсчёта ссылок. Стандартные контейнеры тут не в тему.

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

Я намекал на атомарность, которая необходима для подсчёта ссылок.

Ну начинается. Мы, значит, затребовали от стандартной библиотеки сущность: а) безопасную в случае возникновения исключения; б) с атомарным счётчиком ссылок; и удивляемся чего это столько странного кода у нас появилось. Действительно.

При *разыменовывании* shared_ptr никаких накладных расходов нет: счётчик ссылок не изменяется. Более того, компилятор в некоторых случаях понимает, что в managed-часть можно и не лазить (восславим же, братья, великое UB!).

А во всех остальных случаях накладные расходы можно оценивать только в приложении к конкретной задаче, потому что оптимизация.

А в случае unique_ptr компилятор очень неплохо умеет делать оптимальный код.

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

Ну начинается. Мы, значит, затребовали от стандартной библиотеки сущность: а) безопасную в случае возникновения исключения; б) с атомарным счётчиком ссылок; и удивляемся чего это столько странного кода у нас появилось. Действительно.

Ты гонишь, я ничего ни у кого не требовал. Я лишь сказал, что чувак по ссылке прав, и что RC действительно несёт нетривиальные накладные расходы.

hateyoufeel ★★★★★
()
#include <vector>
#include <iostream>

using namespace std;

template <typename T>
class Object {

public:

	T *inventory;

};

class Inventory {

public:

	vector<Object<Inventory> *> items;

};

class Human: public Object<Inventory> {};

class Sandals: public Object<Inventory> {};

class Socks: public Object<Inventory> {};

int main() {

	auto human = new Human();

	human->inventory = new Inventory();

	human->inventory->items.push_back(new Sandals());
	human->inventory->items.push_back(new Socks());

	cout << "Items count: " << human->inventory->items.size() << endl;

	return 0;

}
Nietzsche
()
Ответ на: комментарий от orkshaman

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

four_str_sam
()
Ответ на: комментарий от RazrFalcon

Ну как минимум этим оправдываются все куцые нововведения.

а ты читал аргументацию-то от членов комитета, почему многие «инновации» в плюсы не попадают? они в открытом доступе, ознакомься и прекращай тупить - там ни слова о сохранении обратной совместимости, в основном крупные фичи не добавляют из-за недоделанности

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

проход при этом задний?

Ещё и твой впридачу, юморист, однопроходный ты наш.

anonymous
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.