Wstępna inicjalizacja obiektu

0

Inicjalizacja zmiennych w plikach nagłówkowych budzi we mnie wiele wątpliwości.

  1. Czy jeśli w pliku .hpp mam int x = 0 i w konstruktorze redefiniuję tę wartość to czy jest to zero-cost?
  2. Czy taka samo inicjalizować skomplikowane obiekty?
  3. Czy w konstruktorze mimo wszystko powinienem definiować te wartości?(w kodzie lepiej widać co mam na myśli)

kod do zobrazowania problemów:

class Foo
{
public:
	// Foo(int x) : x(x) {} // alokacja->inicjalizacja x, czy alokacja->inicjalizacja x->inicjalizacja x?
	Foo(int x = 0, ComplexObject obj = ComplexObject{}) : x(x), obj(obj) {} // `ComplexObject obj = ComplexObject{}` jest to już zdefiniowane wcześniej.
	// konstruktory na górze czy na dole lepsze?
	Foo() = default;
	Foo(int x) : x(x) {}
	Foo(int x, ComplexObject obj) : x(x), obj(obj) {}
private:
	ComplexObject obj{};
	ComplexObject obj1 = ComplexObject(1, 3); // Zwiazane z pytaniem 1 i 2, czy jest to zero-cost? 
	ComplexObject obj2;
	int x = 0;
};
2

https://en.cppreference.com/w/cpp/language/constructor
If a non-static data member has a default member initializer and also appears in a member initializer list, then the member initializer is used and the default member initializer is ignored.

struct S {
    int n = 42;   // default member initializer
    S() : n(7) {} // will set n to 7, not 42
};

Na chłopski rozum: S() : n(7) {} // will set n to 7, not 42 to obiekt tworzy, nie kopiuje. Cokolwiek wpisałeś w ciele klasy nie ma znaczenia.
Foo(int x = 0, ComplexObject obj = ComplexObject{}) : x(x), obj(obj) {} // ComplexObject obj = ComplexObject{} no tu explicite kazałeś mu kopiować, czego się spodziewasz?

5

Radziłbym unikać terminologii, której się nie rozumie. Wygląda na to, że kiedyś usłyszałeś, że w C++ jest "zerro cost abstractions", nie zrozumiałeś o co chodzi i teraz używasz tego terminu w sposób, który wprawia innych w zakłopotanie.

Kod w nagłówku ma jedną podstawową wadę. Bardzo wydłuża czas kompilacji i linkowania.
Główną przyczyną jest to, że kod w nagłówku wymusza dodatkowe zależności nagłówka od innych nagłówków.

Na kod wynikowy ma to różny wpływ. Wszystko zależy od kontekstu: czy to jest biblioteka, jaka i jak jest linkowana, czy to jest nagłówek publiczny.
W najprostszym przypadku nie ma to znaczenia.

Co do samej klasy, zależnie od kontekstu użycia, można zmusić klasę do inicjalizacji w trakcie kompilacji (constexpr), ale ma sens jedynie dla rzeczy o globalnym czasie życia.

0

Czyli w tej sytuacji std::string str = std::string("hello"); nie spowolni programu?

class Foo
{
public:
	Foo() = default;
	Foo(int x) : x(x) {}
	Foo(int x, std::string&& str) : x(x), str(std::move(str)) {}
private:
	std::string str = std::string("hello");
    int x = 0;
};

int main()
{
	Foo foo(5, "xd");
}

Czy definicja klasy Foo jak wyżej jest lepsza, niż ta niżej?

class Foo
{
public:
	Foo(int x = 0, std::string&& str = "hello") : x(x), str(std::move(str)) {}
private:
	std::string str = std::string("hello");
    int x = 0;
};
1

Foo(int x = 0, std::string&& str = "hello") : x(x), str(std::move(str)) {} Matko jedyna, a czemu nie przez wartość skoro move'a robisz i tak?
Obejrzyj to
i to

Ale ogólnie: imho komplikujesz to zanadto. Czy z tym kodem jest problem, że chcesz go już optymalizować?

4

Radziłbym odpuścić sobie mikro optymalizacje, tak jak to nad czym się zastanawiasz.

  1. rzadko kiedy są skuteczne, bo w C/C++ jest zasada AS IF, a wręcz czasami dają efekt odwrotny
  2. naprawdę trzeba dużo wiedzy, żeby to przynosiło jakieś korzyści
  3. Zawsze trzeba mierzyć czy optymalizacje faktycznie działają.

Lepiej spożytkujesz swój czas zapoznając się, z:

  • złożoność obliczeniowa czasowa/pamięciowa - notacja O.
  • jak pisać testy (polecam Catch2 lub gtest)

1 użytkowników online, w tym zalogowanych: 0, gości: 1