Autor Wątek: [C++]Problem z string i nowym Visual Studio  (Przeczytany 973 razy)

Offline MofC

  • Użytkownik

# Luty 09, 2018, 00:52:01
Witam!
Zmieniłem ostatnio IDE z Visual Studio 2015 na 2017 i przeniosłem mój projekt który od dłuższego czasu męczę. W starszym środowisku wszystko działało dobrze ale w nowym mam problem ze stringami. Otóż przy przepisywaniu jednej zmiennej do drugiej wychodzą błędne znaki. Obie zmienne są typem string.

void cGraph::LoadGraph(std::string name, std::string path)
{
[…]
GraphContainer[i].IDname = name;
}

Po operacji ilość znaków w ciągu IDname jest taka sama jak name ale znaki są od razu całkiem inne.
Sprawdzałem debugerem i name do samego przypisania ma prawidłowe dane. Windows SDK mam ustawione na 10.0.16299.0 a zestaw narzędzi na v141. Proszę o pomoc bo nie mam pomysłu co to może być.

Offline Mr. Spam

  • Miłośnik przetworów mięsnych

Offline Lerhes

  • Użytkownik

# Luty 09, 2018, 14:31:11
Cześć MofC,

Mógłbyś podać trochę więcej informacji ?

Może jestem niedowiarkiem, ale mógłbyś pokazać dokładnie jak zadeklarowane jest pole: IDname ?

Cytuj
Po operacji ilość znaków w ciągu IDname jest taka sama jak name ale znaki są od razu całkiem inne.
Możesz sprecyzować co to znaczy, że znaki są całkiem inne? Podaj jakiś przykład jak na przykład mój poniższy:
name jest: "To String"
po przepisaniu w IDname jest: "Je Jablko"
To jest coś w tym rodzaju? Czy może chodzi tylko o Polskie znaki? Jak sprawdzasz, że znaki są całkiem inne? Wypisujesz je? Czy to już w debugerze widać? Co konkretnie widać? Możesz zrobić screen z Visual Studio (w trybie debug) na którym widać zawartość IDname po przepisaniu?

Pozdrawiam,
Lerhes

Offline MofC

  • Użytkownik

# Luty 09, 2018, 18:25:56
Cześć
Więc tak, struktura w której znajduję się pole IDname jest zdefiniowana w nagłówku "Graph.h" i wygląda następująco:

struct Image
{
SDL_Texture* texture;
std::string IDname;

};

Tablica struktur GraphContainer jest umieszczona w klasie cGraph jako pole prywatne. A teraz przykład. Wartość "intro" jest przypisywana do IDname po czym w debugerze widać że IDname zawiera ciąg "ĐCż\x3". Ilość znaków jest taka sama bo pole string.size ma wartość 5 dla obu ciągów.  Dla wartości "menu_background" jest identycznie, IDname="0Dż\x3" i string.size=15.



Offline Lerhes

  • Użytkownik

# Luty 10, 2018, 01:23:25
Cześć MofC,

Ciekawy przypadek tutaj masz. Jakoś nic oczywistego mi nie przychodzi do głowy co mogło  by wyjaśnić twoje wyniki.

Na razie mam dwa strzały: Wielowątkowość oraz błąd debugera.

Aby wykluczyć błąd debugera: Rozumiem, że gra przestała Ci działać na VS2017 i to właśnie przez to, że IDname ma niepoprawnie skopiowanego stringa? Pytam, bo już widziałem przypadek w którym debuger pokazywał nieprawdziwe informacje o stanie zmienych. Albo najlepiej dodaj przed "SDL_Delay(0);" kod:
std::cout << GraphContainer[i].IDname << std::endl;
Aby wykluczyć błąd z wielowątkowością, na wszelki wypadek spróbuj użyć takiego kodu w funkcji LoadGraph:
static SDL_mutex *mutex = 0;

if (mutex == 0)
{
mutex = SDL_CreateMutex();
if (!mutex) {
  fprintf(stderr, "Couldn't create mutex\n");
  return;
}
}

if (SDL_LockMutex(mutex) == 0) {


//Tutaj skopiuj kod z obecnej wersji metody LoadGraph.


  SDL_UnlockMutex(mutex);
} else {
  fprintf(stderr, "Couldn't lock mutex\n");
}



Pozdrawiam,
Lerhes
« Ostatnia zmiana: Luty 10, 2018, 16:40:57 wysłana przez Lerhes »

Offline t4fun

  • Użytkownik

# Luty 10, 2018, 16:07:21
To pewnie nie pomoże, ale mam uwagi do twojego stylu kodu:
- przekazujesz obiekty jako kopie, co nie jest dobrą praktyką, tutaj przekazywałbym jako const ref
void cGraph::LoadGraph(const std::string& name, const std::string& path)- bardzo nie podoba mi się twoje znajdywanie pożądanego obiektu poprzez przeszukanie kontenera pętlą while, jeżeli robisz to co klatkę, to jest to strasznie nie wydajne. Jak to lepiej zrobić trzeba by wiedzieć czym jest ten twój GraphContainer, czy jest to zwykła tablica a może array, a może vector. Zastanów się czy nie mógłbyś wykorzystać mapę lub listę.

W sumie pokaż czym jest i jak inicjujesz GraphContainer, bo to w tym może być twój problem.

Offline MofC

  • Użytkownik

# Luty 10, 2018, 17:15:15
Niestety, to nie jest błąd debuggera. Wypisanie tego stringa do konsoli to potwierdza, choć wynik jest nieco inny niż w debugerze(wynika to pewnie z różnicy w kodowaniu znaków w konsoli i w edytorze).  Co dziwne za każdym razem ten nieprawidłowy ciąg w IDname jest inny dla tej samej przypisywanej wartości.

To chyba też nie problem wielowątkowości. Póki co nie implementowałem żadnej obsługi wątków w kodzie. Przetestowałem twój kod ale to niestety nie pomogło.

Sprawdziłem przekopiowanie całego stringa funkcją memcpy() i wyświetlenie tego w konsoli i zadziałało prawidłowo co chyba oznacza że zarówno z name jak i IDname jest wszystko w porządku.


Cytuj
W sumie pokaż czym jest i jak inicjujesz GraphContainer, bo to w tym może być twój problem.

Bingo. Zerowałem całą tablicę GraphContainer w konstruktorze funkcją ZeroMemory(), skasowałem to i wszystko działa jak powinno. GraphContainer jest zwykłą tablicą struktury Image.


Offline Lerhes

  • Użytkownik

# Luty 10, 2018, 17:47:31
Cześć MofC,

Hehe, zerowanie tablicy struktur jeszcze nie jest takie złe - ale biorąc pod uwagę co masz w tej strukturze (OBIEKT klasy std::string) to nie był najlepszy pomysł. Tym zerowaniem "popsułeś" wewnętrzny stan std::string. Aż dziwne, że Ci się nie wywalało wcześniej (vs2015). W każdym razie - dobrze, że udało się rozwiązać problem.

Pozdrawiam,
Lerhes

Offline MofC

  • Użytkownik

# Luty 10, 2018, 18:13:09
Jak tylko spojrzałem na ten konstruktor to wiedziałem o co chodzi. To zerowanie za pomocą ZeroMemory() dałem wcześniej w ramach eksperymentu a jako że działało to zostawiłem. Jak widać Visual Studio 2017 nie był w stanie znieść czegoś takiego, hehe. W każdym bądź razie dzięki za pomoc.