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

Napisz uniwersalną funkcję swap w języku C++

Object Storage Arubacloud
0 głosów
2,078 wizyt
pytanie zadane 6 grudnia 2019 w C i C++ przez Karolus Użytkownik (510 p.)
Witam obecnie jestem na etapie nauki wskaźników i dynamicznej alokacji pamięci  większość  rzeczy rozumiem, natomiast dostałem zadanie które zabiło mi ćwieka :

Napisz uniwersalną funkcję swap w języku C++ oraz program, który sprawdzi jej działanie dla różnych typów zmiennych.

Czy wie ktoś jak to zrobić? Ja nie mam pomysłów  jedyną podpowiedzią było to że powinienem użyć wskaźnika na void. Proszę o pomoc.
komentarz 6 grudnia 2019 przez adrian17 Ekspert (344,860 p.)

jedyną podpowiedzią było to że powinienem użyć wskaźnika na void

Wtedy w zasadzie piszesz C. Z punktu widzenia C++a zrobienie czegoś takiego brzmi mocno nielegalnie, szczególnie jeśli spróbujesz tą funkcją swapować bardziej złożone typy, szczególnie te z konstruktorami kopiującymi. W C to... może ma sens? Trudno mi powiedzieć, ale brzmi dość podejrzanie.

komentarz 6 grudnia 2019 przez Karolus Użytkownik (510 p.)
Ok ale pomimo tej "nielegalności" można coś takiego stworzyć? Czy mógł byś mi napisać jakby ta funkcja wyglądała ze wskaźnikiem na void?
komentarz 6 grudnia 2019 przez adrian17 Ekspert (344,860 p.)

Gdybym miał strzelać "co prowadzący miał na myśli"... może to?

void swap(void *a, void *b, int size) {
	void *p = malloc(size);
	memcpy(p, a, size);
	memcpy(a, b, size);
	memcpy(b, p, size);
	free(p);
}

int a = 5, b = 4;
swap(&a, &b, sizeof(a));

Natomiast podkreślam:

- to jest naciągany C, a nie C++;

- wyrzuć ten kod natychmiast po oddaniu nauczycielowi i zapomnij o nim; to nie jest materiał do nauki

- ten swap() jest "uniwersalny" dla prostych struktur, ale będzie się sypał segfaultami dla trochę bardziej złożonych typów. Na przykład u mnie kompletnie się wywala dla stringów:

std::string a = "Asdf", b = "xxxx";
swap(&a, &b, sizeof(a));

// Segmentation fault (core dumped)

- nie wiem czy to nauczyciel miał na myśli; ogólnie starej daty nauczyciele często mają różne losowe pomysły... jak widać

komentarz 6 grudnia 2019 przez Karolus Użytkownik (510 p.)
Dzięki bardzo!
komentarz 6 grudnia 2019 przez Karolus Użytkownik (510 p.)
hmm a tego malloc'a nie da się przerobić na new?

2 odpowiedzi

0 głosów
odpowiedź 6 grudnia 2019 przez tkz Nałogowiec (42,000 p.)
edycja 6 grudnia 2019 przez tkz
template <typename T>
void swap(T& a, T& b)
{
    if (a != b)
  {
    a ^= b;
    b ^= a;
    a ^= b;
  }
}
template<typename T> 
void swap(T& t1, T& t2)
 {
    T temp = std::move(t1); 
    t1 = std::move(t2);
    t2 = std::move(temp);
}

 

komentarz 6 grudnia 2019 przez Karolus Użytkownik (510 p.)
OK to jest bardzo blisko tego czego potrzebuje natomiast czy da się to zrobić bez:

template <typename T> ?
komentarz 6 grudnia 2019 przez tkz Nałogowiec (42,000 p.)
Możesz użyć przeciążonych funkcji.
komentarz 6 grudnia 2019 przez adrian17 Ekspert (344,860 p.)
Nie brzmi zbyt uniwersalnie (zadziała tylko na liczbach całkowitych), a sama koncepcja swapa xorami jest dość przestarzała ;)
komentarz 6 grudnia 2019 przez tkz Nałogowiec (42,000 p.)

a sama koncepcja swapa xorami jest dość przestarzała ;)

Dlatego dodałem drugie. 

Nie brzmi zbyt uniwersalnie (zadziała tylko na liczbach całkowitych)

Zadziała również dla innych typów... 

komentarz 6 grudnia 2019 przez adrian17 Ekspert (344,860 p.)

Zadziała również dla innych typów...

Wersja xorowa nie.

Drugą zobaczyłem po tym, jak napisałem odpowiedź ;) Zdjąłem downvote, ale sugeruję dodać w wersji xorowej uwagę że nie jest zbyt uniwersalna i jest bardziej ciekawostką niż odpowiedzią.

komentarz 6 grudnia 2019 przez tkz Nałogowiec (42,000 p.)

Jest prostsza niż wersja z movem, przynajmniej pod względem wiedzy. 

/******************************************************************************

Welcome to GDB Online.
GDB online is an online compiler and debugger tool for C, C++, Python, Java, PHP, Ruby, Perl,
C#, VB, Swift, Pascal, Fortran, Haskell, Objective-C, Assembly, HTML, CSS, JS, SQLite, Prolog.
Code, Compile, Run and Debug online from anywhere in world.

*******************************************************************************/
#include <iostream>
#include <vector>
#include <array>
#include <algorithm>
template <typename T>
void swap(T& a, T& b)
{
    if (a != b)
  {
    a ^= b;
    b ^= a;
    a ^= b;
  }
}


int main()
{
    std::cout<<"int\n";
    {
        int a = 5;
        int b = 10;
        std::cout<<"a "<<a<<" b "<<b;
        swap(a, b);
        std::cout<<"\na "<<a<<" b "<<b;
    }
    std::cout<<"vector\n";
    {
        std::vector<int> a{3,56,2,1,54,2};
        std::vector<int> b{543,51,45,34,2,4};
        std::cout<<"a ";
        for (auto i: a)
            std::cout << i << ' ';
        std::cout<<"\nb ";
        for (auto i: b)
            std::cout << i << ' ';
        swap(a, b);
        std::cout<<"\na ";
        for (auto i: a)
            std::cout << i << ' ';
        std::cout<<"\nb ";
        for (auto i: b)
            std::cout << i << ' ';
    }
    
    return 0;
}

https://onlinegdb.com/HyW0XmuaH

komentarz 6 grudnia 2019 przez adrian17 Ekspert (344,860 p.)
tkz, zauważ że swap na vectorze się skompiluje nawet jeśli usuniesz swoją funkcję. Twój swap jest ignorowany; załącza się ADL i kompilator wybiera std::swap wyspecjalizowany na vectorach.

Twój szablon ogólnie niestety nie ma sensu, bo co operator `^` ma robić na std::vectorze? Nie jest w ogóle zdefiniowany.

Także sugeruję schować ten komentarz :P
komentarz 6 grudnia 2019 przez tkz Nałogowiec (42,000 p.)
Fakt, doczytałem. Działa tylko dla pdo. Nie ukrywam, skoro jest wyjaśnione dlaczego nie działa. Może się komuś przydać.
0 głosów
odpowiedź 6 grudnia 2019 przez adrian17 Ekspert (344,860 p.)
edycja 6 grudnia 2019 przez adrian17

Brzmi jak zwykłe użycie referencji. Czyli

template <typename T>
void swap(T& a, T& b) {

A w środku najprościej będzie zrobić kopię do zmiennej tymczasowej, jak u tkz.

czy da się to zrobić bez:
template <typename T> ?

Nie za bardzo. Szablony są w C++ie narzędziem dokładnie do tego - pisania uniwersalnych funkcji. Ta funkcja jest bardzo uniwersalna, zadziała na w zasadzie wszystkim poza niekopiowalnymi typami.

Swoją drogą, taką samą sygnaturę ma std::swap z biblioteki standardowej.

komentarz 6 grudnia 2019 przez Karolus Użytkownik (510 p.)
To czemu prowadzący ćwiczeń gadał coś o  wskaźniku na void?
komentarz 6 grudnia 2019 przez Karolus Użytkownik (510 p.)
Oh wybacz nie zobaczyłem Twojej odpowiedzi na górze.

Podobne pytania

0 głosów
2 odpowiedzi 869 wizyt
0 głosów
2 odpowiedzi 542 wizyt
0 głosów
1 odpowiedź 3,839 wizyt
pytanie zadane 24 października 2017 w C i C++ przez WRCol Nowicjusz (120 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!

...