Rozmowa kwalifikacyjna - Programista .NET

0

To jak powinien poprawnie wygladać ten kod

CMyObject *pObj = new CMyObject();
pObj->MyMetyhod();
pObj = NULL;
delete pObj;

i czemu tam sie wyciek pojawi?

0

To chyba oczywiste: nie zwalniamy pamięci zaalokowanej na obiekt, bo zanim tą pamięć zwolnimy tracimy wskaźnik na nią (bo przypisujemy mu NULL). Nalezy zamienić dwie ostatnie linijki miejscami...

0
niezalogowany napisał(a)

To jak powinien poprawnie wygladać ten kod

CMyObject *pObj = new CMyObject();
pObj->MyMetyhod();
pObj = NULL;
delete pObj;

i czemu tam sie wyciek pojawi?

Shalom napisał(a)

To chyba oczywiste: nie zwalniamy pamięci zaalokowanej na obiekt, bo zanim tą pamięć zwolnimy tracimy wskaźnik na nią (bo przypisujemy mu NULL). Nalezy zamienić dwie ostatnie linijki miejscami...

Innymi słowy Panu podziękujemy ;-P

0
murzynarktyczny napisał(a)
Krolik napisał(a)

BTW: co do powyższego zadania to oprócz tych 2 błędów, ja bym jeszcze dodał, że używanie makra NULL w C++ to jest "bad style", bo jest zwyczajnie niepotrzebne. Używa się 0. Makro NULL w C++ zwyczajnie nie ma sensu, bo jedyna jego możliwa definicja to:

#define NULL 0

> 
> Lol. Idąc dalej za tą filozofią, WSZYSTKO to syntactic sugar i należy pisać tylko z goto.
> 0 - wartość liczbowa.
> NULL - pusty adres.
> I tak należy pisać. Informujesz wtedy czytającego, co przypisujesz. C++ nie wspiera 'wartości pustej' bezpośrednio - więc to właśnie kwestia dobrego stylu.
> 
> 
```cpp
Klasa {
X *y;
int z;
...
}

jakasMetoda() {
y = NULL; //automatycznie po przeczytaniu - aha, y to wskaznik - jesli chce wiecej szczegolow, najezdzam na nazwe myszką
z = 0; //aha, z to typ liczbowy
}

Podobna sprawa jest z asciiz - dobrym stylem jest pisanie rzeczy w stylu

x[0] = '\0';

zamiast = 0. Ale jeśli zakres jest bardzo mały i deklaracja jest blisko często to olewam.

Problem w tym, że NULL to makro, a nie konstrukcja językowa jak '\0'. I wiążą się z tym wszystkie niebezpieczeństwa używania makr - np. brak jakiegokolwiek wsparcia dla przestrzeni nazw. Kompilator też nie rozróżnia NULL od 0. Dodatkowo możesz mieć poważny problem, gdy ktoś Ci nagle dołączy do projektu jakiś stary header żywcem z C, gdzie była stara definicja #define NULL (void*) 0, i pół programu w C++ nagle przestanie się kompilować. Przy używaniu różnych bibliotek z różnych źródeł bezpieczniej w kodzie C++ wszędzie pisać 0 (zresztą tak zaleca Soustroup w Klasyce C++). Być może czytelność jest nieznacznie większa, ale i tak przed niczym Cię to NULL nie chroni tj. i tak możesz w swoim kodzie napisać:

jakasMetoda() {
y = 0; // wskaźnik nullowy
z = NULL; //przypisujemy zwykłe (int) 0 do zmiennej
}

i wszystko się dalej pięknie kompiluje. Raczej wprowadzasz złudne poczucie bezpieczeństwa takim kodem.

0

Sami widzicie ile można powiedzieć na temat głupich 4 linijek kodu. ;-P

0

Linijki były spoko. Mnie chodziło tylko o samo . zamiast ->, że to już jest niemal jak literówka. Ale już kwestia leaku była jak najbardziej ok.

Swoją drogą ostatnio też przyszedł mi do głowy fajny przykład z życia wzięty:

class CyclicBuffer {
   
private:
    char* buffer;
    size_t length;
    size_t startPos;
    size_t endPos;


public:
    // ... różne duperele jak konstruktory, inicjalizacja danych 

    void addToBuffer(char* data, size_t count);

};

void CyclicBuffer::addToBuffer(char* data, size_t count) {
    if (startPos <= endPos) {

       // tu kilkanaście linijek długiego kodu, napisanego niezbyt porządnie

    }
}

Co jest źle w tej metodzie?

0

brak ; po } zamykającym deklaracji klasy? Czy to tylko twoja literówka? :D

0

Ach, wiedziałem, że ktoś znajdzie głupią literówkę. Sorry. Już poprawiam. Nie o to chodzi.
Zresztą ten kod równie dobrze można napisać w Javie czy C#.

Pytanie testuje, czy ktoś:

  1. wie jak działa bufor cykliczny
  2. umie znajdywać grube błędy przed zagłębieniem się w szczegóły kodu

Punkt 1. należy do wiedzy podstawowej - ktoś kto nie zna podstawowych struktur danych i nie rozumie jak działają hashmapa, wektor, lista łączona czy właśnie bufor cykliczny, nie ma czego szukać w programowaniu. Chyba, że chce całe życie klepać formatki wyświetlające dane z bazy wg tego co zaprojektował projektant.

Zauważyłem też, że punkt 2. jest zaskakująco rzadko spotykaną umiejętnością, a bardzo przydatną. Wielu programistów skupia się na mało istotnych szczegółach, nie widząc wielkiego fuckupu w podstawowej funkcjonalności.

BTW: W zadaniu NIE MA HACZYKA. Zadanie pochodzi z prawdziwego projektu i błąd jest autentyczny.
W ogóle ten projekt dał mi bardzo dużo przykładów na zadania dla kandydatów. Bardzo nie lubię dostawać do rozwiązania problemów "wydumanych", przygotowanych specjalnie żeby zagiąć kandydata. ;]

0

W cyklicznym to raczej nie można założyć, że początek będzie przed końcem.
IMO powinno być != zamiast <=

0

@Loloki: źle, próbuj dalej.

0

Ot chocby brak sprawdzenia czy ten ciąg znaków sie zmieści do bufora, ale to raczej nie to, bo przeciez w tej funkcji moze być nowa alokacja pamięci.

0

Jest sprawdzanie w tej części co napisałem // dużo linijek kodu.
Załóżmy, że ta część jest poprawna. Tzn. też była błędna [rotfl], ale nie umieściłem, bo nie to jest fajnego w tym zadaniu.

0

sprawdzenie czy <= zezwala na równość - gdy start==end, to nie wiadomo czy bufor jest pusty czy pełny i nie wiadomo czy można zapisywać. Powinno być < - warto zachować przynajmniej jeden znak pusty dla pewności.

0

Jesli start <= end to nalezaloby jakos przekrecic startPos, w innnym przypadku metoda zawsze bedzie w tym miejscu zwracac false i wychodzic, nic wiecej nie robiac.

@nav = bufory cykliczny nigdy nie jest pelny, zapetla sie i nadpisuje od poczatku. Tak mi sie przynajmniej wydaje ;d

// zalezy co chcesz osiagnac - moze nie chcesz wersji ktora nadpisuje dane - n

Jak nie chcesz nadpisac to po co cykliczny? Lepiej wtedy producent konsumer czy podobne, i jak konsumer odczyta to reset.

0

Bylo ostrzezenie o off-topicu, goodbye.

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