• Najnowsze pytania
  • Bez odpowiedzi
  • Zadaj pytanie
  • Kategorie
  • Tagi
  • Zdobyte punkty
  • Ekipa ninja
  • IRC
  • FAQ
  • Regulamin
  • Książki warte uwagi

stack.emplace() vs .push()

Object Storage Arubacloud
0 głosów
542 wizyt
pytanie zadane 7 września 2019 w C i C++ przez Teslum_369 Gaduła (4,190 p.)

Witam,

Szukałem na internecie, jaka jest różnica pomiędzy emplace a push. Niestety za dużo nie zrozumiałem, lecz znalazłem fajną informację.:

push() inserts element at index 0 emplace() is used to insert element at specific index

Nom, bardzo fajnie, że się tak dzieje, może to być bardzo pomocne w niektórych sytuacjach. Ale hmm, jak użyć emplace aby wstawić argument na określony index?

2 odpowiedzi

+1 głos
odpowiedź 7 września 2019 przez adrian17 Ekspert (344,860 p.)
wybrane 7 września 2019 przez Teslum_369
 
Najlepsza

W std::stack?

https://en.cppreference.com/w/cpp/container/stack/push

https://en.cppreference.com/w/cpp/container/stack/emplace

Obie robią to samo (wrzucają na stos), tylko push() przekazujesz rzecz do wrzucenia, a emplace() przekazujesz argumenty do skonstruowania elementu.

komentarz 7 września 2019 przez Teslum_369 Gaduła (4,190 p.)
Właśnie, nie do końca rozumiem co znaczy "argumenty do  skonstruowania elementu". Mam rozumieć, iż nie jest to kopiowane, czyli na ogół emplace jest szybszy od push? Tak jeszcze dodając, czy jest wgl możliwe użycie emplace do wrzucenia na stos, tylko, że do określonego indexu?
komentarz 7 września 2019 przez tkz Nałogowiec (42,000 p.)
Teoretycznie emplace jest szybszy o ile używasz konstruktora, push pcha kopie obiektu.
komentarz 7 września 2019 przez Teslum_369 Gaduła (4,190 p.)
Dzięki tkz, a jak się sprawa ma z tymi indexami?
komentarz 7 września 2019 przez adrian17 Ekspert (344,860 p.)

Jeśli masz jakiś złożony obiekt który chcesz skonstruować i wrzucić na stack, z push zrobiłbyś:

std::stack<klasa> stos;

stos.push(klasa(1, "asdf", 6));
// lub:
klasa rzecz(1, "asdf", 6);
stos.push(rzecz);

Czyli konstruujesz rzecz i musi zostać przekopiowana, by znalazła się w środku kontenera. Może to spowodować niepotrzebne wywołania copy/move constructora.

Z emplace:

stos.emplace(1, "asdf", 6);

Od razu wywołuje konstruktor "na miejscu". Może to być szybsze przy strukturach z kosztownym copy construktorem (gdy move nie jest możliwy).

komentarz 7 września 2019 przez adrian17 Ekspert (344,860 p.)

Tak jeszcze dodając, czy jest wgl możliwe użycie emplace do wrzucenia na stos, tylko, że do określonego indexu?

Po to jest stos, żeby dało się go tylko uzywać jak stos ;) Jeśli chcesz możliwość dodawania/usuwania/iteracji w arbitralnych miejscach, użyj zwykły std::vector.

komentarz 7 września 2019 przez tkz Nałogowiec (42,000 p.)

Użyczę sobie linku Adriana, stack nie posiada czegoś takiego jak sobie wyobrażasz https://en.cppreference.com/w/cpp/container/stack, nie możesz odnieść się do wybranego indexu. Taka zasada stosu LIFO 

komentarz 7 września 2019 przez vector Dyskutant (9,200 p.)
edycja 7 września 2019 przez vector

Właśnie, nie do końca rozumiem co znaczy "argumenty do  skonstruowania elementu".

n3690

§23.6.5.2 stack definition

namespace std {
template <class T, class Container = deque<T>> class stack {
  // ...
  Container c;
public:
  // ...
  template <class... Args> void emplace(Args &&... args) {
    c.emplace_back(std::forward<Args>(args)...);
  }
};

Zakładając że Containter to deque więc jest to kontener sekwencyjny. Teraz wystarczy popatrzeć na

§23.2.3 sequence containers

// edit, wkleiłem złą tabelke ;p

expression:
a.emplace_back(args)

 

return type:
void

 

Effects:
Appends an object of type T constructed with std::forward<Args>(args)....

 

Requires:
T shall be EmplaceConstructible into X from args.

czyli to oznacza że "argumenty do  skonstruowania elementu" muszą spełniać warunek: T shall be EmplaceConstructible into X from args.

 

czy jest wgl możliwe użycie emplace do wrzucenia na stos, tylko, że do określonego indexu?

Nie, wystarczy jeszcze raz popatrzeć na §23.6.5.2 stack definition

+1 głos
odpowiedź 7 września 2019 przez tangarr Mędrzec (154,860 p.)

push() powoduje skopiowanie przekazanego argumentu.
emplace() utworzenie elementu w odpowiednim miejscu na podstawie przekazanych argumentów.

Najlepiej poznać to na żywym przykładzie

#include <iostream>
#include <stack>

class X {
public:
    X(int liczba, std::string napis);
    X(const X& other);
private:
    int mLiczba;
    std::string mNapis;
};

X::X(int liczba, std::string napis) :
    mLiczba(liczba),
    mNapis(napis)
{
    std::cout << "Konstruktor " << liczba << " " << napis << std::endl;
}

X::X(const X &other) :
    mLiczba(other.mLiczba),
    mNapis(other.mNapis)
{
    std::cout << "Konstruktor kopiujacy " << mLiczba << " " << mNapis << std::endl;
}

int main() {
    std::stack<X> stack;
    std::cout << "Test push()" << std::endl;
    stack.push(X(1, "jeden"));
    std::cout << "Test emplace()" << std::endl;
    stack.emplace(2, "dwa");
    return 0;
}

Zwróć uwagę na argumenty przekazane do funkcji push() i emplace()

Output:

Test push()
Konstruktor 1 jeden
Konstruktor kopiujacy 1 jeden
Test emplace()
Konstruktor 2 dwa

 

1
komentarz 7 września 2019 przez j23 Mędrzec (194,920 p.)

push() powoduje skopiowanie przekazanego argumentu.

Bardziej precyzyjnie: powoduje skopiowanie lub przeniesienie przekazanego argumentu.

komentarz 7 września 2019 przez tangarr Mędrzec (154,860 p.)
Tym przeniesieniem mnie zaskoczyłeś.
Zrobiłem eksperyment dodałem konstruktor przenoszący.
Kompilator wybiera lepszy konstruktor na podstawie kontekstu.
Myślałem, że push przeniesie obiekt tylko jeżeli użyjemy std::move().
Łapaj plusika.
komentarz 7 września 2019 przez j23 Mędrzec (194,920 p.)

std::move używa się tylko wtedy, gdy chce się wymusić przeniesienie, bo np. obiekt jest l-wartością. W Twoim przykładzie dodawany obiekt jest obiektem tymczasowym (r-wartość), dlatego kompilator wybiera wariant push z r-referencją.

Podobne pytania

0 głosów
1 odpowiedź 180 wizyt
pytanie zadane 15 marca 2023 w C# przez Whyyy Nowicjusz (240 p.)
+4 głosów
2 odpowiedzi 575 wizyt
pytanie zadane 1 kwietnia 2018 w Offtop przez jeremus Maniak (59,720 p.)
0 głosów
0 odpowiedzi 148 wizyt
pytanie zadane 27 października 2022 w Android, Swift, Symbian przez AnimaVillis Stary wyjadacz (11,510 p.)

92,576 zapytań

141,426 odpowiedzi

319,652 komentarzy

61,961 pasjonatów

Motyw:

Akcja Pajacyk

Pajacyk od wielu lat dożywia dzieci. Pomóż klikając w zielony brzuszek na stronie. Dziękujemy! ♡

Oto polecana książka warta uwagi.
Pełną listę książek znajdziesz tutaj.

Akademia Sekuraka

Kolejna edycja największej imprezy hakerskiej w Polsce, czyli Mega Sekurak Hacking Party odbędzie się już 20 maja 2024r. Z tej okazji mamy dla Was kod: pasjamshp - jeżeli wpiszecie go w koszyku, to wówczas otrzymacie 40% zniżki na bilet w wersji standard!

Więcej informacji na temat imprezy znajdziecie tutaj. Dziękujemy ekipie Sekuraka za taką fajną zniżkę dla wszystkich Pasjonatów!

Akademia Sekuraka

Niedawno wystartował dodruk tej świetnej, rozchwytywanej książki (około 940 stron). Mamy dla Was kod: pasja (wpiszcie go w koszyku), dzięki któremu otrzymujemy 10% zniżki - dziękujemy zaprzyjaźnionej ekipie Sekuraka za taki bonus dla Pasjonatów! Książka to pierwszy tom z serii o ITsec, który łagodnie wprowadzi w świat bezpieczeństwa IT każdą osobę - warto, polecamy!

...