Care About Your Craft: Why spend your life developing software unless you care about doing it well? - The Pragmatic Programmer
C++ och dess framtid att programmera minnessäkert - Hur går utvecklingen?
Du får ursäkta men vad vinner påstå att andra som inte delar dina åsikter för att de trollar, lite barnsligt om man får lov och vara tydlig.
Du får gärna säga att du tycker jag har fel, att en lösning är sämre än en annan. Men vill du jag skall lyssna så behöver du också veta varför. Och då bör du veta vad du pratar om, inte att du läst det eller någon berättat för dig.
Det är fullt av utvecklare som lärt sig "så här är det" men förstår inte varför eller om de lärt fel.
Jag är beredd att hålla med om att du är ett troll när du inte vill svara på frågor utan bara kommer med nya kontroversiella utfästelser baserat på ditt tyckande. Om du istället faktiskt svarade på de frågor du får så skulle vi kunna debattera saker vi har olika åsikter om. Men när våra frågor resulterar i att du styr över diskussionen till något annat är det svårt.
Jag är beredd att hålla med om att du är ett troll när du inte vill svara på frågor utan bara kommer med nya kontroversiella utfästelser baserat på ditt tyckande. Om du istället faktiskt svarade på de frågor du får så skulle vi kunna debattera saker vi har olika åsikter om. Men när våra frågor resulterar i att du styr över diskussionen till något annat är det svårt.
Tror du seriöst att någon kommer svara dig när du spottar fram en-meningsfrågor eller kommentarer där man får fundera länge över vad du menar?
Vill du ha svar så får du tänka igenom och förstå att skall någon svara dig så ber du om en annan persons tid, den personen behöver tycka det är värt att lägga tid på dig
Just det faktum att du envisas med att inte använda standardkomponenter som std::vector för din buffer, gör inte det att det blir mer kod som måste läsas och förstås och memoreras?
Använder du en debugger när du rättar eller testar kod?
Du får ursäkta men vad vinner påstå att andra som inte delar dina åsikter för att de trollar, lite barnsligt om man får lov och vara tydlig. Du får gärna säga att du tycker jag har fel, att en lösning är sämre än en annan.
Jag tycker det är ganska barnsligt att du kommer med massa tvivelaktiga påstående och när du konfronteras så besvarar du en bråkdel av frågorna och sedan börjar yra om något helt annat och kommer med nya tvivelaktiga påstående. Detta ser jag som att du trollar.
Men vill du jag skall lyssna så behöver du också veta varför. Och då bör du veta vad du pratar om, inte att du läst det eller någon berättat för dig.
Det är fullt av utvecklare som lärt sig "så här är det" men förstår inte varför eller om de lärt fel.
Du har vid mer än ett tillfälle name-drop:at och länkat koncept som du inte har läst eller saknar förståelse för och jag tror att det är fler än jag som tycker att du är personen som inte har koll på sina saker, exempelvis när du länkade till regressionstester på Wiki eller när du pratar om deklarativ kod.
Eftersom du ironiskt insinuerar att folk inte kan något med du själv gett bevis på att du inte kan sakerna som du pratar om så ser jag även detta som att du trollar.
Det märks
Du bör tolka detta som att du uttrycker dig otydligt och osammanhängande snarare än komplext.
Känner du till begreppet "data orienterad design" som blir vanligare och vanligare inom programmering?
Ytterligare ett begrepp, du är konsekvent osammanhängde iaf... Jag känner till begreppet. Har du något bevis för att det blir vanligare inom programmering generellt?
Exakt vad data orienterad design är beror på vem du frågar men tror det börjar forma sig något till en gemensam förklaring. Såg en bra artikel om det för ett tag sedan, skall se om jag kan hitta den
Du har alltså inte en klar bild av begreppet? Jag tycker att jag har en tydlig bild av begreppet. Du behöver inte leta upp den för jag behöver inte ett sidospår till.
Jag tycker att jag har en tydlig bild av begreppet.
Det har du inte för det finns ingen, försök gärna bevisa det om du har något
Det har du inte för det finns ingen, försök gärna bevisa det om du har något
Du följer inte Jonathan Blow misstänker jag?
Du följer inte Jonathan Blow misstänker jag?
Jag vet vem det är och sett lite av han, menar du att dit bevis är en annan persons åsikter?
Jag vet vem det är och sett lite av han, menar du att dit bevis är en annan persons åsikter?
Han är en stor förespråkare av data-oriented design med en del inflytande så ja min åsikt är väl ärvd från honom.
menar du att dit bevis är en annan persons åsikter?
Ja, delvis. Jag vet inte vad du pratar om bevis, jag kan inte minnas att jag har lagt fram något bevis mer än att jag har en mental bild av ett koncept. Hur så?
Tror du seriöst att någon kommer svara dig när du spottar fram en-meningsfrågor eller kommentarer där man får fundera länge över vad du menar?
Tidigare i tråden skrev jag ett antal ganska långa inlägg, men eftersom du inte svarar på de frågor jag ställer utan i svävar ut i resonemang om ovidkommande ämnen har jag gett upp att skriva långa frågor. Vad är det du inte förstår? Jag har försökt vara konkret och tydlig i mina frågeställningar, inte lämna utrymme för utsvävningar om annat.
Vill du ha svar så får du tänka igenom och förstå att skall någon svara dig så ber du om en annan persons tid, den personen behöver tycka det är värt att lägga tid på dig
Your Honor, I rest my case.
Tidigare i tråden skrev jag ett antal ganska långa inlägg, men eftersom du inte svarar på de frågor jag ställer utan i svävar ut i resonemang om ovidkommande ämnen har jag gett upp att skriva långa frågor. Vad är det du inte förstår?
Är det detta inlägget du menar?
#20733907
Tolkade inte det som en specifik fråga till mig utan mer allmänt tyckande
Och jag ber om ursäkt här med för såg precis att detta svar till dig var menat till @orp
Har tryckt fel
Han är en stor förespråkare av data-oriented design med en del inflytande så ja min åsikt är väl ärvd från honom.
Ja, delvis. Jag vet inte vad du pratar om bevis, jag kan inte minnas att jag har lagt fram något bevis mer än att jag har en mental bild av ett koncept. Hur så?
Ber om ursäkt för jag läste din tidigare text fel, vart lite för snabb.
Ok. Ja inom spel har de en tanke bakom "data oriented design" för de är mer eller mindre tvingade till det. Men tekniken går att använda överallt. Till och med för vanliga frontendlösningar.
Ber om ursäkt för jag läste din tidigare text fel, vart lite för snabb.
Ingen fara, alla gör missar.
Ok. Ja inom spel har de en tanke bakom "data oriented design" för de är mer eller mindre tvingade till det. Men tekniken går att använda överallt. Till och med för vanliga frontendlösningar.
Jag förstår att man kan använda på mängder av ställen men jag har svårt att hänga med vilken diskussion detta hör till men jag misstänker effektivitet. Jag ser dock som spelutveckling som ett nischat case. Majoriteten av kod som jag skriver kräver inget extraordinärt, det är vardagliga saker som läs från X, skriv till Y, icke-prestandakritiska datatransformeringar dvs saker som kräver vardagliga lösningar som inte hade gynnats avsevärt av data oriented design.
Jag förstår att man kan använda på mängder av ställen men jag har svårt att hänga med vilken diskussion detta hör till men jag misstänker effektivitet.
Kanske OT här men om vi tar frontend som är lååångt från spelutveckling angående krav på prestanda.
Frontendare idag, där är det mer regel än undatag att man automatiskt väljer ett ramverk och det faller ofta på react.
Den typen av programmering kallar jag för deklarativ programmering, att man skriver så lite logik som möjligt och förlitar sig på färdigskriven kod. Javscriptkomponenter eller teknik i browsern.
Ett problem med dessa komponenter är att de nästan alltid hanterar datan. Det är svårt att skriva en "enkel" komponent som bara är att dra in i valfritt projekt om den har ett annat beroende. Och de som använder färdigskriven kod vill inte sitta och lära sig innan de kan testa.
Frontend är framförallt användargrafik (gränssnitt mot användaren) i form av html/css.
Gränssnitt och data är två olika saker, blandas två olika saker blir det mycket svårare att återanvända.
Exempel:
Tabeller är vanligt in frontendlösnignar. Finns massor av olika tabellkomponenter att hämta om man inte vill bygga en egen. Tabeller behöver rendera sin data som ofta ligger i något tabelformat (kanske vektor som håller vektorer för varje rad).
I DOD (data orienterad design) hade man aldrig blandat tabellens data med gränssnittet. Hade ett DOD valts som teknik för att producera gränssnittet hade troligen en slags tabeldata klass skapats. Det enda denna klass haft till uppgift hade varit att hantera data. Kanske sortera kolumner, filtrera rader, markera om värden ändrat sig och så vidare. Inget med gränssnitt utan ren databehandling.
Gränssnitt som visar tabellens data byggs sedan på tabelldata klassen. Logiken för data blandas inte med tabellens logik för att rendera data i browserna utan istället hämtar den bara informationen från en generell tabelldataklass.
Med en sådan lösning kan man snabbt bygga nya gränssnitt för det är inte så svårt, dessa komponenter jobbar mot en och samma tabelldataklass.
Tabelldataklassen kan få mer och mer funktionalitet, eftersom den inte är beroende av gränssnittet så kan alla komponenter som jobbar mot tabeldataklassen ockskå dra nytta av logiken som läggs till.
Ett exempel på data orienterad design enligt mig.
Att bygga logik kring data som inte är domänspecifik. Gränssnitt är i princip alltid domänspecifika.
Samma lösning gjorda med ramverk, exempelvis react. Innan programmerare där kan jobba i kod måste de lära sig domänen och det tycker de flesta är tråkigt. Det tar också tid innan de blir effektiva eftersom de måste lära sig regelverket för domänen.
Oftast kallas sådana domänlösningar för "domain driven design".
Ovanstående är också ett exempel på varför det krockar mellan olika programmerare.
Att göra en reactlösning går snabbt men blir det fel måste man göra om
Att göra en dataorinterad lösning tar längre tid men blir det designmissar behöver man inte göra om (inte alls lika mycket)
Låter som att det du förespråkar är i princip en klassisk uppdelning som använts för många system i många decennier.
Å ena sidan har du en generell datahanteringsdel med generell kod för datastrukturer, som t.ex. STL i C++, eller en databasmotor som MySQL.
Sen har man ett domänspecifikt lager med affärslogik, som använder sig av datadelen, och visar information med presentationslagret.
Och sist ett presentationslager, som kan vara en websida med HTML, eller ren text, eller grafer, etc. Behöver inte vara särskilt domänspecifikt.
Lätt hänt att man blandar ihop två eller fler av ovanstående delar, men det är ingen lysande idé.
Men, oavsett hur man delar upp sitt program, om gör man en designmiss så behöver man göra om en del saker.
Låter som att det du förespråkar är i princip en klassisk uppdelning som använts för många system i många decennier.
Japp, det märkliga är att om man idag förespråkar den typen av lösning blir det genast många som hoppar högt
Programmering idag är så extremt deklarativ, så var det inte förr
För en programmerare är det naturligt att välja programmeringslösnignar och tänka data
Å ena sidan har du en generell datahanteringsdel med generell kod för datastrukturer, som t.ex. STL i C++, eller en databasmotor som MySQL.
Stämmer men de lösningar jag varit med och byggt och byggt egna (eget) objekt för att hantera data internt. Istället för att ha flera strukturer används ett enda tabellobjekt som blir en teknik för att transportera databasdata internt i applikationen.
Sen har man ett domänspecifikt lager med affärslogik, som använder sig av datadelen, och visar information med presentationslagret.
Och sist ett presentationslager, som kan vara en websida med HTML, eller ren text, eller grafer, etc. Behöver inte vara särskilt domänspecifikt.
Desto tunnare lager för domänen desto bättre. Domänkod ändrar sig alltid och det kan bli stora ändringar. Görs C++ lösningar bör man helt flytta ut domänen i något scriptspråk, exempelvis LUA och eventuellt läsa in metakod (kanske i xml eller json format).
C#, java och liknande där väljs ofta att bygga in domänen i java eller C# kod men då behöver man bygga en ny backendlösning för varje nytt system och ändringar i domänen kan ofta kräva att man behöver bygga om backendlösningen.
Lätt hänt att man blandar ihop två eller fler av ovanstående delar, men det är ingen lysande idé.
Passar på att skicka upp en text i ämnet
https://rentry.co/ytg6npms
Känner du till Microsofts COM (component object model)
Och du har helt rätt i att denna COM teknik inte gillas av många C++ gurus men Windows är fulllproppad med den och enligt mig så har tekniken varit helt central för att Windows har kunnat skala upp till de enorma mängder funktionalitet operativet besitter
Inledde min jobbkarriär som Windows-systemprogrammerare och COM/DCOM var en av de saker jag specifikt satte mig in i rejält. Är rätt ringrostig i det idag då jag inte jobbat med det på >20 år.
Fråga: är DU med på vad som är den huvudsakliga poängen med COM (och varför DCOM blev ett sådant enormt fiasko)?
Givet att tråden egentligen handlar om C++ och dess framtid p.g.a. brister i minnessäkerhet, kan man ju nämna att likt C++ så har COM fortsatt att vara otroligt viktigt trots att den tekniken också ligger bakom en lång rad säkerhetsrelaterade problem i Windows, MS Office, m.fl. Toppen på det var ActiveX, att låta webbsidor aktivera COM-objekt gick att använda till en del coola saker men var ett totalt säkerhetshaveri och ingen blev nog förvånad när det togs bort.
COM är en Windows-specifik lösning på det som gjort C, och inte C++, till programmeringsvärldens "lingua franca". En binärspecifikation av vtable formatet. C++ saknar en stabil/standardiserad ABI, något C har och som nära nog alla språk (inklusive C++ och Rust) använder i deras FFI.
Det viktiga här är inte nakna pekare, det viktiga är en stabil ABI. Finns "smarta pekare" för COM till C++ (vet inte om ATL, Active Template Library, finns kvar men var populärt runt millennieskiftet). Idag lär det mesta som jobbar med COM vara .NET-applikationer och där blir det ju inte heller nakna pekare utan "normal" .NET hantering via IDisposable och "vanliga" .NET interface.
Så vad är din poäng med COM i detta kontext?
Inledde min jobbkarriär som Windows-systemprogrammerare och COM/DCOM var en av de saker jag specifikt satte mig in i rejält. Är rätt ringrostig i det idag då jag inte jobbat med det på >20 år.
Fråga: är DU med på vad som är den huvudsakliga poängen med COM (och varför DCOM blev ett sådant enormt fiasko)?
Hur menar du att COM varit ett fiasko? COM har ju varit och är helt centralt för Windows och man kan väl ändå inte påstå att Windows är ett fiasko
Blanda inte ihop DCOM med COM och där har IP och internet tagit över
Givet att tråden egentligen handlar om C++ och dess framtid p.g.a. brister i minnessäkerhet, kan man ju nämna att likt C++ så har COM fortsatt att vara otroligt viktigt trots att den tekniken också ligger bakom en lång rad säkerhetsrelaterade problem i
Windows, MS Office, m.fl. Toppen på det var ActiveX, att låta webbsidor aktivera COM-objekt gick att använda till en del coola saker men var ett totalt säkerhetshaveri och ingen blev nog förvånad när det togs bort.
Hur går ordspråket, "if all you have is a hammer, everything looks like a nail". COM är bra men det är inte bra för allt
COM togs fram under Microsofts storhetstid, då de hade som bäst utvecklare och jag skulle nog säga att mellan 1994 - 2005, då var de som hetast sedan har det gått utför.
Under denna tiden var de innovativa, kom med egna lösningar istället för att härma. När man gör egna lösningar kommer man också göra mycket fel. Det kostar att testa och man måste våga.
Att ActiveX i en browser var mindre smart skall man enligt mig inte kritisera Microsoft för, bra att de vågade. Microsofts problem kanske var att om de prövade något och det vart fel blev också konsekvenserna enorma med tanke på deras storlek.
COM är en Windows-specifik lösning på det som gjort C, och inte C++, till programmeringsvärldens "lingua franca". En binärspecifikation av vtable formatet. C++ saknar en stabil/standardiserad ABI, något C har och som nära nog alla språk (inklusive C++ och Rust) använder i deras FFI.
C++ är "syntax sugar" för C, så stor skillnad är det inte. Ok det finns en del men en C programmerare som kan bolla med minnet kan göra saker väldigt likt som man kan göra i C++.
Mycket av C++ kod brukar generalisera C api, det var inte svårt att bygga in COM i C++ med smart pointers och annat.
ATL vart ett välanvänt klassbibliotek
Det viktiga här är inte nakna pekare, det viktiga är en stabil ABI.
Beror väl på vad du skall göra. Kommunikation mellan komponenter i Linux eller andra unix relaterade system är ingen höjdare heller. Och firefox (mozilla) tror jag gjorde en egen implementation av COM, samma företag som tog fram rust om jag är rätt ute
Så vad är din poäng med COM i detta kontext?
Den lilla lösningen jag presenterade som hämtade data från databas, den är inte så liten och den använder vtables för att koppla ihop komponenter. Om man gör en lösning tycker jag alltid man skall leta efter något liknande för hittas något liknande kan man också härma och använda dokumentationen kring det. Att göra något 100% själv är ingen bra lösning för det finns då bara i utvecklarens eget huvud.
När generella interface skrivs måste de klara mycket, så mycket som möjligt för annars måste man snart lägga till nya metoder. De skrivs därför inte för att vara bra C++ kod utan de skrivs för att kunna pluggas in. Det blir då mycket pekare och annat (alltså adresser). I COM finns en hel del void* pekare som du vet.
Lösningen kan jobba mot valfri databas och använder en slags tabellklass för att transportera data. Massor är gjort för det och det går att bygga en rätt avancerad backendlösning på någon månad. Helt webserver och mm
Ja varför tror du att C och C++ inte väljer att lägga allt i en vector exempelvis för du har helt rätt i det, det går att lägga det mesta i en vector.
Varför C programmerare inte gör det är enkelt, C saknar RAII.
Varför man inte skulle göra det i C++ begriper jag inte givet att RAII är en av C++ mest positiva finesser.
Om det nu är "en gäng bytes som ligger sekventiellt" man behöver (vilket var exakt fallet i ditt exempel) så har jag faktiskt väldigt svårt att se någon bättre sätt att hantera just den delen än std::vector<uint8_t> / Vec<u8>. Finns absolut ingen fördel och flertalet nackdelar med att jobba med (pekare, storlek, kapacitet).
Om vi tar problematik med linux och rust, varför en del C programmera inte vill ha in rust koden eller för att ta citatet från denna välskrivna artikel
Although superficially that doesn’t look particularly bad, as a C person this makes my eyes bleed. Let’s leave aside the headache of specifying the memory management in the declaration of the structure in a convoluted way,
Du tycker en artikel är "välskriven", specifikt det exempel där han försöker visa hur dåligt Rust är och samtidigt lyckas göra något som är UB i C (trots ett otroligt enkelt exempel)?
Har du sett något annat C++ projekt som väljer att använda std::vector för att hantera allt minne?
vector är vanligt men jag tror det är extremt ovanligt att vector används som allmän buffer.
Nu har de flesta lågnivå bibliotek jag jobbat med varit skrivna i C, inte C++. Men en av de första rimliga abstraktioner man bör göra i en C++ wrapper är att hantera buffertar på ett sätt så RAII fixar livslängd och std::vector<char>/std::vector<uint8_t> är ett exempel på lämpligt val.
Mycket lättare att använda kod/APIer som använder RAII på ett korrekt sätt, t.ex. undvika "use-after-free" som i "verkligheten" tyvärr är en allt för vanlig bug (och inte sällan då ett säkerhetshål) i C och C++ kodbaser.
Förstår inte, tvärtom skulle jag vilja säga. En del utvecklare gör det fasligt svårt för sig. Trasslar in sig i massa konstigheter
Det går inte att skriva kod så den måste läsas/memoreras om man skall skriva mycket. Ingen klarar att minnas flera hundra tusen rader kod, än mindre miljoner. Är koden skriven på det viset vilket är ganska lätt att upptäcka så vet man att de inte kommer speciellt långt. Och det beror alltså på att koden inte följer fasta mönster, koden skiljer sig från ett ställe till ett annat och ofta en del hack.
När koden skrivs så går det ofta snabbt i början, sedan går det långsammare och så går det ännu långsammare. Efter ett tag börjar programmerare tappa orken för det är mentalt mycket ansträngde att arbeta i kod som inte är byggd för att skala. Programmerare måste fokusera så hårt på att minnas saker istället för vad de tycker är skoj vilket ofta är att skapa
Du menar som att skriva så här
std::string stringDbName = GetApplicationFolder();
stringDbName += "db.sqlite";
gd::database::database_i* pdatabase = (gd::database::database_i*)new gd::database::sqlite::database_i("db");
auto result_ = pdatabase->open({ {"file", stringDbName} });
gd::database::cursor_i* pcursor = nullptr;
pdatabase->get_cursor(&pcursor);
result_ = pcursor->open("SELECT * FROM TCustomer;");
gd::table::dto::table tableCustomer;
gd::database::to_table(pcursor, &tableCustomer);
std::string stringResult;
gd::table::to_string(tableCustomer, stringResult, gd::table::tag_io_header{}, gd::table::tag_io_csv{});
std::cout << stringResult << "\n";
i stället för t.ex. så här (orkade bara fixa de mest uppenbara grodorna)
auto stringDbName = GetApplicationFolder() + "/db.sqlite";
auto pdatabase = std::make_unique<gd::database::sqlite::database_i>("db");
if (!pdatabase->open({ {"file", stringDbName} })) {
std::cerr << "Failed to open database.\n";
return -1;
}
std::unique_ptr<gd::database::cursor_i> pcursor;
if (!pdatabase->get_cursor(&pcursor) || !pcursor) {
std::cerr << "Failed to get database cursor.\n";
return -1;
}
if (!pcursor->open("SELECT * FROM TCustomer;")) {
std::cerr << "Failed to execute query.\n";
return -1;
}
gd::table::dto::table tableCustomer;
gd::database::to_table(pcursor.get(), &tableCustomer);
std::string stringResult;
if (!tableCustomer.empty()) {
gd::table::to_string(tableCustomer, stringResult, gd::table::tag_io_header{}, gd::table::tag_io_csv{});
std::cout << stringResult << "\n";
} else {
std::cerr << "No data found in the table.\n";
}
Går inte att veta från ursprungliga koden om de nakna pekarna är "här är minnet, det är ditt problem nu" (i.e. unique_ptr<>) eller "här är en delad referens till minnet, säg till när du är klar" (i.e. shared_ptr<>), eller möjligen en COM-referens (som då bör ha anropat add() innan och jag som mottagare ska anropa release() när man är klar).
Ursprungliga koden är ett rejält haveri för någon som inte känner till alla underliggande detaljer då det inte räcker att bara läsa det som visas här för att veta vad som behövs göras för att undvika minnesläckor, UB, etc. Givet hur då går på om att "ingen kan komma ihåg allt i stora kodbaser", är det inte uppenbart då vilka brister ditt exempel har? Brister som tyvärr är väldigt vanliga i C och C++ kodbaser, vilket vi ser i den stora andelen "säkerhetsrelaterade buggar".
"Modern C++" kan undvika det mesta, men det är opt-in och finns tyvärr folk som fortsätter trampa på i gamla spår med "gammal C++". Rust har den stora fördelen här att det inte ens går att kompilera kod med sådana brister men mindre än att ta till "unsafe".
Care About Your Craft: Why spend your life developing software unless you care about doing it well? - The Pragmatic Programmer
Varför C programmerare inte gör det är enkelt, C saknar RAII.
Det är massor syntactic sugar som C saknar ja, men C kod är jättelätt att läsa. Jag förstår absolut de som ogillar C++ framför C. Att läsa C kod och man förstår nära nog exakt vad som händer. C går abstrahera något otroligt och gömma saker så koden blir mer eller mindre omöjlig att följa. Är inte jättesvårt att skriva smart C++ kod så annan deklarativ C++ slaktar python i abstraktionsnivå.
i stället för t.ex. så här (orkade bara fixa de mest uppenbara grodorna)
Plockade koden från ett test och tog bort en del för att fokusera på funktionaliteten. Context är viktigt
Samma kod i produktion har en hel hög med saker inbakat givetvis. Fyller liten funktion att klistra in sådant här.
Om det nu är "en gäng bytes som ligger sekventiellt" man behöver (vilket var exakt fallet i ditt exempel) så har jag faktiskt väldigt svårt att se någon bättre sätt att hantera just den delen än std::vector<uint8_t> / Vec<u8>. Finns absolut ingen fördel och flertalet nackdelar med att jobba med (pekare, storlek, kapacitet).
Använder du debugger?
Debugvänlig kod slår läsbarhet eller säkerhet när det gäller sådant här och det är också viktigt att följa mönster när kod skrivs.
Samma typ av logik. "Hackig" kod gör inte vana utvecklare.
Enda gången man läser koden igen är om ny funktionalitet skall in eller att koden debuggas.
Om jag uppskattar så skrevs klassen på strax under en dag, hade jag gjort den med vector tror jag inte det skulle spara tid.
Jag har läst massor av annan C++ och kan inte komma ihåg att jag sett en enda gång att någon använder std::vector som generell minneshanterare. Tror att 10 av 10 C++ utvecklare värdesätter och prioriterar flexibilitet snarare än att riskera bygga in sig i en svårmodifierad lösning. (nu vet jag vad du tänker, men tänk på att C++ utvecklare inte tänker som rust utvecklare)
Går inte att veta från ursprungliga koden om de nakna pekarna är "här är minnet, det är ditt problem nu" (i.e. unique_ptr<>) eller "här är en delad referens till minnet, säg till när du är klar" (i.e. shared_ptr<>), eller möjligen en COM-referens (som då bör ha anropat add() innan och jag som mottagare ska anropa release() när man är klar).
Det är inte meningen heller. och interface "släpps" med release som du också nämner
Använder du debugger?
Debugvänlig kod slår läsbarhet eller säkerhet när det gäller sådant här och det är också viktigt att följa mönster när kod skrivs.
Samma typ av logik. "Hackig" kod gör inte vana utvecklare.
Enda gången man läser koden igen är om ny funktionalitet skall in eller att koden debuggas.
Om jag uppskattar så skrevs klassen på strax under en dag, hade jag gjort den med vector tror jag inte det skulle spara tid.
Well, ja?
Och det är väl ett ännu större argument för att använda något som ger mer kontext då alla relevant debuggers har sedan väldigt långt tillbaka explicit stöd för STL.
Tar vi detta exempel
#include <print>
#include <vector>
template <typename T>
T sum(const std::vector<T> &v)
{
T s = T{};
for (auto elem : v)
s += elem;
return s;
}
template <typename T>
T sum(const T *const p, size_t sz)
{
T s = T{};
for (auto i = 0; i < sz; i++)
s += p[i];
return s;
}
int main()
{
std::vector v{1, 2, 3, 4, 5};
v.reserve(10);
auto fGradePtr = new int[10]{1, 2, 3, 4, 5};
std::print("Sum of {} is {}\n", v, sum(v));
std::print("Sum of {:#x} is {}\n", reinterpret_cast<ptrdiff_t>(fGradePtr), sum(fGradePtr, 5));
delete[] fGradePtr;
}
så visas informationen om man använder std::vector<> så här
mot detta
Finns inget som är bättre med alternativ 2 och det är inte heller på något sätt snabbare/mer effektivt
Det "enkla" sättet att skriva ut med std::print ger
Sum of [1, 2, 3, 4, 5] is 15
Sum of 0x143004130 is 15
så ingen fördel där heller.
Jag har läst massor av annan C++ och kan inte komma ihåg att jag sett en enda gång att någon använder std::vector som generell minneshanterare. Tror att 10 av 10 C++ utvecklare värdesätter och prioriterar flexibilitet snarare än att riskera bygga in sig i en svårmodifierad lösning. (nu vet jag vad du tänker, men tänk på att C++ utvecklare inte tänker som rust utvecklare)
Så du har aldrig använt nätverk/IO via boost och/eller jobbat med Unreal Engine? Boost buffers är kompatibelt med std-containers och TArray<> i UE är i praktiken deras variant av std::vector<> och är normalsättet att hantera minne.
Care About Your Craft: Why spend your life developing software unless you care about doing it well? - The Pragmatic Programmer
Well, ja?
För mig är debuggern det helt avgörande när jag väljer miljö att utveckla i. Det finns en del som skriver C++ kod och inte använder debuggern, istället skriver de ut värden och kompilerar om. Det går ju bara bort på 0.1 sekund. Den typen av utveckling fungerar inte mer än om man möjligen sitter med små skol eller hobbyprojekt. En gissning är att de lärt sig koda på universitet eller liknande och där är det inte så noga hur kod skrivs, mer att de lyckas lösa något.
Utvecklare måste använda debuggern om de skall förstå och minimera antalet buggar.
Inom frontend är det än vanligare att inte använda debuggern i browsern exempelvis, typiskt för utvecklare som kör react eller annat ramverk. När de inte använder debuggern så räkna med att det blir många buggar som behöver fixas.
Om man jobbat i team och de exempelvis kör morgonmöten eller andra regelbundna samlingar så går det ibland att märka bara på hur aktiva olika är på mötena. Om utvecklare är lite si och så vad gäller att skriva buggfri kod, de brukar hela tiden ha massa saker att göra medan de som kan skriva bättre kod har mycket mindre att göra.
Chefer/ansvariga som eventuellt inte kan programmera eller förstår programmering, de fattar inte alltid utan tolkar detta som "oj vad duktiga de är som kämpar så". De tystare utvecklarna som gör rätt från början uppfattas tvärtom om kanske lite lata.
Menar inte att det alltid är så här men jag har sett det några gånger.
Säger en utvecklare "jag vill inte använda debuggern", kanske för att den tränat in andra tekniker. Då måste den utvecklaren tänka om eller förstå att produktivitet aldrig kan bli speciellt bra.
Personligen väljer jag nästan alltid Visual Studio och utveckla med för där är debuggern överlägsen. VS Code är inte alls lika bra och VS code är så seg också när projekten växer. Den fungerar för frontend men inte C++ mer än för mindre projekt.
Sublime Text brukar jag använda i frontend. Den är snabb men har inte så mycket funktionalitet självklart. Men man slipper bli irriterad på att smågrejjer tar några sekunder extra.
Och det är väl ett ännu större argument för att använda något som ger mer kontext då alla relevant debuggers har sedan väldigt långt tillbaka explicit stöd för STL.
Det är det inte. Exempelvis undviker jag att använda std::unique_ptr just på grund av att den är lite jobbigare att debugga och jag tycker inte det är svårt med minne. Den typen av buggar har jag inte, kan knappt komma ihåg sist jag skulle ha en smäll för att minne lästes på fel adress. Om inte annat så lär sig C och C++ programmerare hur detta måste hanteras när de skriver debugkod och utvecklar ny funktionalitet.
Enda jag kan komma ihåg sett till minne är för drygt två år sedan. Skrev funktionalitet som använde sprintf. Och då så i linux med GCC använde sprintf en större buffer än med CL och LLVM i windows. Minns jag rätt så skiljde det på en byte när den skrev double värden (men är osäker nu vad det var för värde).
Tar vi detta exempel
Ser ut som vs code, debuggern där är inte bra Jag hovrar de flesta värden och vill gärna kunna se vad det är då.
I VS code fungerar det knappt och man behöver klicka upp nästan allt som inte är primitiva värden.
Med det sagt så självklart blir det också problem med att debugga om man sköter buffern själv som "uint8_t" puBuffer". Nu är denna strings klass ganska enkel men så här skriver jag ofta kod (observera NDEBUG)
Och så använder jag också onödigt många variabler, det är för att kunna hovra värden vid debug. Detta är saker som kompilatorn optimerar bort ändå. Att skriva smarta en-rads funktionalitet är att göra sig själv en björntjänst
/** ---------------------------------------------------------------------------
* @brief Replaces the string at the given puPosition with a new string.
*
* This method manages the replacement of a string within a custom string buffer
* where each string is prefixed with its length in 32-bit unsigned integer format,
* and the data is stored in 32-byte aligned blocks.
*
* @param puPosition Pointer to the position where the string should be replaced. The position must be at the 32-bit length before string.
* @param stringReplace The new string to replace the existing one.
*
* @details
* - **Buffer Management**:
* - Checks if the new string requires more space than the existing one; if so,
* it ensures the buffer has enough capacity by potentially increasing its size.
* - If the new string's block size differs from the old one, it shifts the data
* following the replacement point to maintain buffer integrity.
*
* - **Assertions**:
* - Ensures the position for replacement is within the buffer's bounds.
*
* @pre
* - `puPosition` must be a valid pointing to a position within the string buffer.
* - `stringReplace` should not exceed the maximum size that can be represented by `uint32_t`.
*
* @post
* - The content at `puPosition` is replaced with `stringReplace`.
* - If necessary, the subsequent data in the buffer is shifted, and `m_uSize` is updated accordingly.
*/
void strings32::replace( uint8_t* puPosition, const std::string_view& stringReplace)
{ assert( puPosition >= buffer() ); assert( puPosition < buffer_end() ); assert( (puPosition - buffer()) % 4 == 0 );
#ifndef NDEBUG
std::string_view string_begin_d( c_str_s( puPosition ), length_s( puPosition ) );
auto uLength_d = length_s( puPosition );
#endif
// ## Get the position of the string to replace and calculate the block sizes
uint64_t uOffset = puPosition - m_puBuffer; // Offset of the string to replace
uint8_t* puReplacePosition = puPosition; assert( puReplacePosition < buffer_end() ); assert( puReplacePosition >= buffer() );
uint32_t uOldLength = *reinterpret_cast<uint32_t*>(puReplacePosition); // uOldLength: Length of the existing string
uint32_t uOldBlockSize = align32_g(uOldLength + (uint32_t)sizeof(uint32_t));// uOldBlockSize: Total block size of the existing string
// ## Calculate the new block size and check if the buffer can accommodate the new string
uint32_t uNewLength = static_cast<uint32_t>(stringReplace.size()); // uNewLength: Length of the new string
uint32_t uNewBlockSize = align32_g(uNewLength + (uint32_t)sizeof(uint32_t)); // uNewBlockSize: Total block size required for the new string
int64_t iSizeDifference = static_cast<int64_t>(uNewBlockSize) - static_cast<int64_t>(uOldBlockSize); // iSizeDifference: Difference between new and old block sizes
// ## Check if the new block is larger than the old one, then make sure the buffer can accommodate the extra bytes and update position
if( iSizeDifference > 0 )
{
reserve_add(static_cast<uint64_t>(iSizeDifference));
puReplacePosition = buffer() + uOffset; assert( puReplacePosition < buffer_end() ); assert( puReplacePosition >= buffer() );
}
// ## Check if there is any size difference, then shift the subsequent data to accommodate the new block size
if( iSizeDifference != 0 ) // If there is any size difference
{
uint8_t* puSource = puReplacePosition + uOldBlockSize; // puSource: Pointer to the data after the old block
uint64_t uMoveSize = m_uSize - (puSource - m_puBuffer); // uMoveSize: Number of bytes to move to adjust for the size change, it's the size from start of value to end of buffer that is used
memmove(puSource + iSizeDifference, puSource, uMoveSize); // Shift the subsequent data to accommodate the new block size
m_uSize += iSizeDifference; // Update the used buffer size after the replacement
}
*reinterpret_cast<uint32_t*>(puReplacePosition) = uNewLength; // Write the new string length into the block header
puReplacePosition += sizeof(uint32_t); // Move the pointer to the start of the string data
memcpy(puReplacePosition, stringReplace.data(), uNewLength); // Copy the new string data into the block
#ifndef NDEBUG
std::string_view string_d( (const char*)puReplacePosition, uNewLength );
uLength_d = (uint32_t)string_d.size();
#endif
}
är det svårare saker kan debug kod vara nära hälften av all kod. Blir det fel om ett år när man glömt av och det skulle smälla måste det vara lätt att förstå exakt vad som görs. Därav är sådan här kod väldokumenterad också
För mig är debuggern det helt avgörande när jag väljer miljö att utveckla i.
Du får det att låta som att debuggern på något vis är hårt knuten till utvecklingsmiljön. Jag kör neovim och har debugger så jag tror att du kan välja bland en rad olika miljöer utan att oroa dig för debuggern. Jag kan välja mellan att gdb eller codelldb.
Det finns en del som skriver C++ kod och inte använder debuggern, istället skriver de ut värden och kompilerar om.
Kallas printf/print-debugging.
En gissning är att de lärt sig koda på universitet eller liknande och där är det inte så noga hur kod skrivs, mer att de lyckas lösa något.
Nu kommer du med vilda gissningar igen. I min universitetsutbildning ingick iaf debugger, kodstil och arkitektur.
Inom frontend är det än vanligare att inte använda debuggern i browsern exempelvis, typiskt för utvecklare som kör react eller annat ramverk. När de inte använder debuggern så räkna med att det blir många buggar som behöver fixas.
Webbutvecklar du och har något bevis för att backa detta? Min browser har en debugger iaf och jag misstänker att den existerar där för folk som utvecklar för webben ...
Om man jobbat i team och de exempelvis kör morgonmöten eller andra regelbundna samlingar så går det ibland att märka bara på hur aktiva olika är på mötena. Om utvecklare är lite si och så vad gäller att skriva buggfri kod, de brukar hela tiden ha massa saker att göra medan de som kan skriva bättre kod har mycket mindre att göra.
Detta låter också som ett märkligt antagande. Du tror inte att det har att göra med personlighet introvert/extrovert än kodkvalitet? Alternativt att vissa är av en tillfredsställande personlighetstyp som åtar sig för många uppgifter och därför har för många "bollar i luften"?
Chefer/ansvariga som eventuellt inte kan programmera eller förstår programmering, de fattar inte alltid utan tolkar detta som "oj vad duktiga de är som kämpar så". De tystare utvecklarna som gör rätt från början uppfattas tvärtom om kanske lite lata.
Eller så ser cheferna engagemanget hos dom som är aktiva och tolkar de andra som oengagerade. Min teori är att chefer ofta är mer extroverta och därför gillar energin från extroverta utvecklare. En bra chef måste se/förstå alla i teamet.
Säger en utvecklare "jag vill inte använda debuggern", kanske för att den tränat in andra tekniker. Då måste den utvecklaren tänka om eller förstå att produktivitet aldrig kan bli speciellt bra.
Det handlar troligen om bekvämlighet. En stor andel problem går att lösa med printf-debugging men om man upptäcker att man själv befinner sig i en sits där man strösslar printar över kodbasen så bör man inse att debuggern hade varit ett bättre alternativ.
Personligen väljer jag nästan alltid Visual Studio och utveckla med för där är debuggern överlägsen. VS Code är inte alls lika bra och VS code är så seg också när projekten växer. Den fungerar för frontend men inte C++ mer än för mindre projekt.
Det är troligen samma debugger i Visual Studio och VSCode medans frontend(webb)-debuggern ligger i browsern(om jag inte är fel på det).
Här kommer jag nog avrunda mitt svar. Det känns som du har väldigt mycket fördomar och väldigt svårt att hålla dig till ämnet. Är det dags att vi kopplar in en moderator för att låsa tråden för att slippa vidare OT?
MASSA FRÅGOR...
Jag hoppas du förstår att det inte går att svara på alla dina frågor, har annat att göra och tror inte det allmänna intresset för vad du frågar om är så stort.
Angående frontend (ramverk och debugga). Jag har inte "bevis" men det går att dra slutsatser och jag har jobbat på ett ställe som hade många frontendutvecklare.
Varför jag inte tror det är vanligt att de använder debugger beror på att dessa ramverk är gjorda så utvecklare skall skriva deklarativ kod. Det är motsatsen till imperativ utveckling. Två helt olika yrken (om du frågar mig). Målet för en deklarativ utvecklare är ofta att skriva så lite kod som möjligt. Koden som skrivs är i princip alltid hårdkodad och är inte skriven för underhåll. Det är inte lika viktigt att debugga deklarativ kod, där handlar det mycket mer om att minnas vad man gjort då det är mycket domänspecifika lösningar och namn kopplade till domänen.
Imperativ kodning, där är målet att abstrahera så mycket som möjligt så den domänspecifika delen blir enklare att hantera.
Finns massor av projekt som inte begripit detta och domänen följer med djupt ner i techstacken. Det som händer då är att kodmängden exploderar i storlek. +100 tabeller i en databas och bli inte förvånad om det finns + 100 000 rader kod endast för att skyffla data fram och tillbaka mellan dessa tabeller och klientens gränssnitt.
---
"Kallas printf/print-debugging"
Har det ett namn också :). Oavsett så är det bedrövligt dålig teknik. Debuggern är en utvecklares viktigaste verktyg. Om en programmerare inte tycker debuggern är viktig har aldrig skrivet någon svårare kod.
Jag hoppas du förstår att det inte går att svara på alla dina frågor, har annat att göra och tror inte det allmänna intresset för vad du frågar om är så stort.
Jag förstår och jag vill mest bemöta fördomarna.
Angående frontend (ramverk och debugga). Jag har inte "bevis" men det går att dra slutsatser och jag har jobbat på ett ställe som hade många frontendutvecklare.
Varför jag inte tror det är vanligt att de använder debugger beror på att dessa ramverk är gjorda så utvecklare skall skriva deklarativ kod. Det är motsatsen till imperativ utveckling. Två helt olika yrken (om du frågar mig). Målet för en deklarativ utvecklare är ofta att skriva så lite kod som möjligt. Koden som skrivs är i princip alltid hårdkodad och är inte skriven för underhåll. Det är inte lika viktigt att debugga deklarativ kod, där handlar det mycket mer om att minnas vad man gjort då det är mycket domänspecifika lösningar och namn kopplade till domänen.
Imperativ kodning, där är målet att abstrahera så mycket som möjligt så den domänspecifika delen blir enklare att hantera.
Nu är ju två nära vänner till mig webbutvecklare så jag vet ju om att webbutvecklare även skriver en hel del JavaScript och inte enbart HTML och CSS.
Du behöver inte förklara deklarativ och imperativ kod för mig när jag tidigare tillrättavisat din användning av deklarativ kod.
"Kallas printf/print-debugging"
Har det ett namn också :). Oavsett så är det bedrövligt dålig teknik. Debuggern är en utvecklares viktigaste verktyg. Om en programmerare inte tycker debuggern är viktig har aldrig skrivet någon svårare kod.
Jag tror att utvecklare tycker att debuggern är bra men jag tror samtidigt att du lägger för stor vikt vid debuggern och ser det som någon prestige-sak över utskrifter.
Personligen tycker jag att det kvittar om folk använder debugger eller printf så länge problemet blir löst.
Oavsett nu svävas det ut igen. Du vill inte starta en tråd om "Debuggers vs printf-debugging" där detta kan diskuteras vidare? Jag misstänker att en del webbutvecklare hade deltagit och kunnat ge sin bild av debugging i en sådan tråd istället för en C++-tråd om minnessäkerhet.
Jag tror att utvecklare tycker att debuggern är bra men jag tror samtidigt att du lägger för stor vikt vid debuggern och ser det som någon prestige-sak över utskrifter.
Det här är ingen subjektiv åsikt utan det är objektiv fakta. En person kan bara komma ihåg så många variabler och det finns en gräns i hur många "bollar" man samtidigt kan ha koll på. Det tar tid att skriva in kod för att debugga så det det går att räkna ut att utvecklarens gräns till vad som går att lösa minskar drastiskt.
Det tar också tid, är det buggar som kräver ett förlopp innan man når buggen kan det spenderas dagar endast för att rätta en bugg och det är mentalt mycket mer ansträngande.
Då kan man kanske ha ett motargument som att man inte skall skriva för "svår" kod. Eller låta bli "smarta" lösningar. Men det som då glöms är att enklare kod ofta är samma sak som mycket mer kod.
Vad imperativa utvecklare gör är att förenkla, det går inte alltid att skriva enkelt för att lösa svårare problem.
Förutom att debuggen är fantastisk för att hitta buggar är det också bra teknik för att se missar man gjort som kanske inte leder till någon bugg men ändå behöver fixas till.
Debuggern är också kanon om man vill lära sig annan kod, kod man inte skrivit själv.
Tänk på att i Visual Studio kan man backa i koden (känner inte till att de fått till det i VS Code eller om det går när det blir krångligare).
Backa = gå tillbaka och köra om kod utan att avsluta debug sessionen
Det här är ingen subjektiv åsikt utan det är objektiv fakta. ...
Det är ju också ett naivt och oerfaret sätt att se på saken.
Om du ska debugga ett problem med nätverkskommunikation där du stundvis får korrekta men oväntade meddelande och där det finns klient-timeouts. Kommenterar ut klient-timeouts:en och spenderar timmar med att steppa eller du lägger till en print/log-entry?
Då kan man kanske ha ett motargument som att man inte skall skriva för "svår" kod. Eller låta bli "smarta" lösningar. Men det som då glöms är att enklare kod ofta är samma sak som mycket mer kod.
Nej, du har gett exempel på detta i tråden. @Yoshman var enklare, mindre benägen till fel och var ungefär samma mängd kod.
Vad imperativa utvecklare gör är att förenkla, det går inte alltid att skriva enkelt för att lösa svårare problem.
Nu använder du imperativ på ett märkligt sätt igen i ett felaktigt påstående ... med den logiken så skulle en utvecklare förlora sin förmåga att förenkla problem om dom lär sig Haskell eller Erlang?
Nej, du har gett exempel på detta i tråden. @Yoshman var enklare, mindre benägen till fel och var ungefär samma mängd kod.
Och hade samma kod skrivits i java eller kanske python hade den varit ännu enklare. Så varför går inte alla över till python där man knappt behöver vara programmerare för att skriva kod?
Tänk på att i Visual Studio kan man backa i koden (känner inte till att de fått till det i VS Code eller om det går när det blir krångligare).
Backa = gå tillbaka och köra om kod utan att avsluta debug sessionen
Det är fortfarande en debugger feature och har inte så mycket med IDEn att göra. IDEn är inblandad så till vida att den kan rendera debugger info åt dig i GUI:t och ger dig en knapp/keybinding som säger åt att skicka info till debuggern som sedan ger ett svar tillbaka till IDEn som då uppdaterar GUI:t. Min uppfattning är att antingen erbjuder IDEn en wrapper runt GDB eller snackar DAP med lldb/codelldb/gdb.
Det är fortfarande en debugger feature och har inte så mycket med IDEn att göra. IDEn är inblandad så till vida att den kan rendera debugger info åt dig i GUI:t och ger dig en knapp/keybinding som säger åt att skicka info till debuggern som sedan ger ett svar tillbaka till IDEn som då uppdaterar GUI:t. Min uppfattning är att antingen erbjuder IDEn en wrapper runt GDB eller snackar DAP med lldb/codelldb/gdb.
Fråga: Om en utvecklare inte använder debuggern. Utvecklaren har kanske producerat 1000 rader kod under en vecka, hur vet utvecklaren att koden fungerar? Skulle du känna dig säker på att det är kvalitet i koden om du vet att utvecklaren inte använder en debugger?
Och jag kan inte låta bli att nämna det.... Vi sitter just nu och skriver i en tråd som handlar om att C++ inte är säkert för att det går att manipulera minnet och hur mycket bättre rust är för det där inte går samtidigt försvarar du utvecklare som låter bli att använda en debugger.
Det är vad jag kallar för "att sila mygg och svälja kameler"
- PostNord stoppar tillfälligt USA-försändelser87
- Nya högtalare, behöver tips!2
- Populär Chrome-VPN avslöjad - spionerar på användare48
- Microsoft bekräftar SSD-problem30
- Ingen respons från Webhallen187
- Ugoos AM6B+ - Ultimata Dolby Vision mediaspelaren216
- 5800 processor läker liquid metal12
- Vem reparerar fristående bildskärmar?26
- SweClockers - Marknadsreferenser (läs första inlägget innan du postar!)14k
- Problem med undertexter (video)1
- Skänkes Förstärkare: Boss Katana 50 MK2
- Skänkes Dator: Ryzen 5 2600X, RTX 2060
- Skänkes Dator: i7-7700K, GTX 1080
- Säljes Audeze Maxwell
- Säljes DELL Latitude 5500 |i5-8265U|256GB SSD|8GB DDR4|Win 11
- Skänkes Noctua anti-vibration pads
- Säljes Prusa 3D-skrivare MK3S+
- Köpes Söker efter Mini pc
- Säljes Ryzen 5800x, RX 6700XT, i3 13100F moderkort osv
- Säljes 4080 ROG strix white edition
- AMD läckte FSR 4-kod - stöd för äldre kort kan vara på väg13
- Populär Chrome-VPN avslöjad - spionerar på användare48
- 5K2K-upplösning vid 180 Hz i ny Samsung-skärm34
- Microsoft bekräftar SSD-problem30
- Gigabyte lanserar externt RTX 5090 med vätskekylning12
- Quiz: Vad är det för hårdvarumojäng på bilden?91
- Microsoft minskar spelladdningsstid med 85 procent9
- Sårbarhet i flera populära lösenordshanterare67
- Valve-prototyp dyker upp på Geekbench17
- Radeon RX 9070 är augusti månads mest prisvärda grafikkort37
Externa nyheter
Spelnyheter från FZ