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

use of deleted function - poprawna składnia i problem

VPS Starter Arubacloud
0 głosów
1,677 wizyt
pytanie zadane 12 sierpnia 2016 w C i C++ przez niezalogowany

Witam, mam klasę, która wygląda mniej więcej tak:

class Music
{
    int type;
    sf::Music song;
public:
    Music(int _type, int volume);
    int return_type();
    void stop();
    void start();
};

Ponadto tworzę sobie wektor tej klasy i do tego momentu wszystko się kompiluje, wówczas gdy próbuję wrzucić coś do niego to wyrzuca mi masę błędów pokroju:

C:\Program Files (x86)\CodeBlocks\MinGW\lib\gcc\mingw32\4.9.2\include\c++\bits\stl_construct.h|75|error: use of deleted function 'Music::Music(Music&&)'|

Music.h|6|error: use of deleted function 'sf::Music::Music(const sf::Music&)'|

Zupełnie nie wiem o co chodzi, nigdy nie miałem tego typu problemów, na ovestacku coś pisali o wyłączeniu domyślnego konstruktora i o ile dobrze zrozumiałem to ten sposób nie działa (w .h Music()=delete;)

4 odpowiedzi

0 głosów
odpowiedź 12 sierpnia 2016 przez MetRiko Nałogowiec (37,110 p.)
wybrane 12 sierpnia 2016
 
Najlepsza

Prawdopodobnie błąd ten jest spowodowany przez brak konstruktora: 
sf::Music::Music(const sf::Music&);
Twórcy SFML'a najwyraźniej go usunęli z jakiegoś powodu (domyślnie taki konstruktor zawsze tworzy kompilator, chyba że osoba pisząca kod wyraźnie zaznaczy, że takiego konstruktora nie chce).
Jako, że std::vector wykorzystuje dokładnie ten konstruktor przy dodawaniu nowego elementu.. niemożliwe jest jego użycie (wektora). 
W takim wypadku masz dwie możliwości, jednak w obydwu przypadkach wektor będzie musiał przechowywać tylko wskaźniki, a nie całe obiekty.
Tak więc.. Albo tworzysz wcześniej obiekt typu sf::Music, a następnie do wektora v_musics wstawiasz wskaźniki do tego obiektu, albo używasz operatora new w celu przechowywania obiektu typu sf::Music..
Osobiście polecam drugie rozwiązanie..
vector<Music*> v_musics;
v_musics.push_back(new Music(dane1, dane2)): 

Dodam jeszcze, że podobna sytuacja występuje przy obiektach typu sf::Texture.. ale to tak na przyszłość.

komentarz 12 sierpnia 2016 przez niezalogowany
Najlepiej wytłumaczona odpowiedź ale jeszcze Cię pomęcze skoro orientujesz się w tym temacie, no dobra tyle, że do końca nie moge powiedzieć, że to jest obiekt typu sf::Music, przecież ma on w sobie chociażby też dane int, dobrze myślę? Podobnie by było gdybym miał obiekt w którym bym miał teksturę, sprajta, i muzykę, obiekt to obiekt, pewien zlepek jakiś właściwości pochodzących od klasy, tak? Tylko, że w takim razie miałem już niejednokrotnie sytuacje gdzie obiekt miał w sobie tylko sprajta lub sprajta i teksturę i problem ten nie występował, czemu?
komentarz 12 sierpnia 2016 przez niezalogowany
i teraz przez tę zmianę nie do końca się orientuje jak mam używać tego wektoru, np:

if(v_musics.size()==2&& v_musics.begin()->return_type()==(v_musics.end()-1)->return_type()) mam sobie takiego ifa, n to wyrzuca mi błąd taki:

error: request for member 'return_type' in '* v_musics.std::vector<_Tp, _Alloc>::begin<Music*, std::allocator<Music*> >().__gnu_cxx::__normal_iterator<_Iterator, _Container>::operator-><Music**, std::vector<Music*> >()', which is of pointer type 'Music*' (maybe you meant to use '->' ?)|

 

Nie do końca się orientuje co teraz
komentarz 12 sierpnia 2016 przez MetRiko Nałogowiec (37,110 p.)

Załóżmy, że mamy obiekt typu Res, który zawiera obiekt typu NonCopyable (bez konstruktora NonCopyable(const NonCopyable&); )
struct Res
{
    int Variable;
    NonCopyable Object; 
    Res(int val, int data):Variable(val),Object(data){;}
}

W takim wypadku możliwy jest taki zapis:
Res NewRes(10, 20);
Jednak taki już wywoła błąd:
Res OldRes(10 ,20);
Res NewRes=OldRes;
//Błąd kompilacji
Wynika to z tego, że przy wykorzystywaniu operatora '=' kompilator korzysta z konstruktora Res(const Res&); (z tego samego konstruktora podczas przypisywania obiektu korzysta std::vector) jednak należy wiedzieć jak ten konstruktor działa.. mianowicie.. Ten, który jest tworzony domyślnie kopiuje wszystkie wartości ze starego obiektu do nowego.. w naszym wypadku zapis:
Res NewRes=OldRes;
(W dużym skrócie) wywoła takie operacje:
NewRes.Variable = OldRes.Variable;
NewRes.Object = OldRes.Object;
//błąd kompilacji.. tutaj kompilator próbuje wywołać konstruktor Object(const Object&), jednak okazuje się, że on nie istnieje dlatego przypisanie nie może nastąpić co skutkuje błędem kompilacji.
Odsyłam do tego linka.. tu jest dokładnie napisane jakie jest zadanie konstruktora domyślnego: http://stackoverflow.com/questions/563221/is-there-an-implicit-default-constructor-in-c
A teraz prosty przykład:
http://cpp.sh/4wqq

komentarz 12 sierpnia 2016 przez MetRiko Nałogowiec (37,110 p.)
Oto odpowiedź na twój drugi problem : )
http://cpp.sh/5tnga
0 głosów
odpowiedź 12 sierpnia 2016 przez Patryk Krajewski Nałogowiec (26,170 p.)
W jaki sposób próbujesz coś wrzucić do tego wektora i jak go tworzysz? Wrzuć tu kod
komentarz 12 sierpnia 2016 przez niezalogowany
vector<Music> v_musics

v_musics.emplace_back(dane1, dane2)
komentarz 12 sierpnia 2016 przez MetRiko Nałogowiec (37,110 p.)

Spróbuj użyć metody push_back(...).
Wyglądałoby to tak:
vector<Music> v_musics;
v_musics.push_back(Music(dane1, dane2));

komentarz 12 sierpnia 2016 przez niezalogowany
dalej ten sam błąd
0 głosów
odpowiedź 12 sierpnia 2016 przez obl Maniak (51,280 p.)

Nie masz zaimplementowanego odpowiedniego konstruktora, zobacz przykład z strony tutaj.

#include <vector>
#include <string>
#include <iostream>
 
struct President
{
    std::string name;
    std::string country;
    int year;
 
    President(std::string p_name, std::string p_country, int p_year)
        : name(std::move(p_name)), country(std::move(p_country)), year(p_year)
    {
        std::cout << "I am being constructed.\n";
    }
    President(President&& other)
        : name(std::move(other.name)), country(std::move(other.country)), year(other.year)
    {
        std::cout << "I am being moved.\n";
    }
    President& operator=(const President& other) = default;
};
 
int main()
{
    std::vector<President> elections;
    std::cout << "emplace_back:\n";
    elections.emplace_back("Nelson Mandela", "South Africa", 1994);
 
    std::vector<President> reElections;
    std::cout << "\npush_back:\n";
    reElections.push_back(President("Franklin Delano Roosevelt", "the USA", 1936));
 
    std::cout << "\nContents:\n";
    for (President const& president: elections) {
        std::cout << president.name << " was elected president of "
                  << president.country << " in " << president.year << ".\n";
    }
    for (President const& president: reElections) {
        std::cout << president.name << " was re-elected president of "
                  << president.country << " in " << president.year << ".\n";
    }
}

Musisz utworzyć dla swojej klasy konstruktor:

Music(Music&& other)

który w zasadzie jest konstruktorem kopiującym.

komentarz 12 sierpnia 2016 przez niezalogowany
robiłem wiele razy tak jak dotychczas i nigdy taki błąd niewystępował :/
0 głosów
odpowiedź 12 sierpnia 2016 przez criss Mędrzec (172,590 p.)

std::vector::push_back wykorzystuje kosntruktor kopiujący, ale od c++11 jest też push_back przyjmujące referencje do rwartości (rvalue reference) i z tego możesz skorzystać skoro konstruktor kopiujący jest delete. Najlepiej jakbyś pokazał jak wygląda u ciebie dodawanie do vectora (pokaż linie kodu). 

Anyway, jeśli klasa nie ma konstruktora kopiującego, to masz musisz skorzystać z push_back(Typ&&):

//v to vector
v.push_back(Klasa()); // od razu podajesz mu rvalue
//albo:
Klasa k; 
/* coś robisz z tym obiektem
a nastepnie zmuszasz push_back aby potraktował go jako rvalue: */
v.push_back(std::move(k));
// po tym absolutnie już nie ruszaj obiektu k, bo konstruktor przenoszący pozostawił 
// go w niezdefiniowanym stanie
// zakładam, że to sie dzieje w jakiejś funkcji i k jest obiektem lokalnym, który
zniknie po wyjściu z funkcji

Drugą możliwością jest skorzystanie z emplace_back również dostępnego od c++11. Emplace back przyjmuje argumenty, które następnie zostaną przekazane do zwykłego konstruktora i emplace_back sama sobie stworzy obiekt na końcu kontenera.

np.:

class A
{
  public: A(int, float, std::string) { } 
};

std::vector<A> v;
v.emplace_back(1, 1.f, "lkfjlsf");

 

Podobne pytania

0 głosów
1 odpowiedź 245 wizyt
0 głosów
1 odpowiedź 522 wizyt
0 głosów
1 odpowiedź 159 wizyt
pytanie zadane 23 stycznia 2023 w C i C++ przez Marcinuq Użytkownik (690 p.)

92,834 zapytań

141,778 odpowiedzi

320,827 komentarzy

62,164 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

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!

...