C++ frågor

C, C++, Pascal, Assembly, Raspberry, Java, Matlab, Python, BASIC, SQL, PHP, etc.
Mr Andersson
Inlägg: 1394
Blev medlem: 29 januari 2011, 21:06:30
Ort: Lapplandet

Re: C++ frågor

Inlägg av Mr Andersson »

Jo private är det mest lämpliga. Då är de skyddade från (o)avsiktliga ändringar då bara klassfunktionerna kan komma åt dem.
Att designa en bra inkapsling utan att överkomplicera programstrukturen kan vara knepigt men en bra grundregel är; Om programmet kan krascha eller göra dåliga saker om variabeln ändras utifrån använd private (eller protected vid behov)
Användarvisningsbild
4kTRB
Inlägg: 18289
Blev medlem: 16 augusti 2009, 19:04:48

Re: C++ frågor

Inlägg av 4kTRB »

Ok men då går det inte deklarera static under private: ?

static double allocbuf[STACKSIZEMAX];
static double* stackTopPointer;

class StackDouble {
public:
StackDouble(int);
bool allocdouble();
void push(double);
double pop(void);
void testit(double*);
private:
int stackSize;
};

Sedan en annan fråga:

Från main vill jag anropa så här...

Kod: Markera allt

double v[2];
	v[0] = 2.5;
	v[1] = 3.5;
	stackDouble_000.testit(v);
till funktionen....

Kod: Markera allt

void StackDouble::testit(double* p){
	cout << *(p) << NEWLINE;
	cout << *(p+1) << NEWLINE;
}
Det jag önskar är att i funktionen extrahera storleken hos v
för att därigenom deklarera en buffert allocbuf[2] i klassen.
Eller kanske helt enkelt kopiera v till allocbuf. Jag är ute efter att
komma ifrån deklarationen
static double allocbuf[STACKSIZEMAX];
jag vill sätta storleken på allocbuf från main.

Är detta möjligt eller omöjligt?
Jag ser inga andra möjligheter att få till en dynamiskt valbar storlek på allocbuf.
Användarvisningsbild
mankan
EF Sponsor
Inlägg: 905
Blev medlem: 18 juli 2015, 11:23:22
Ort: Linköping

Re: C++ frågor

Inlägg av mankan »

Labba lite med std::vector så kan du nog lösa det.
Användarvisningsbild
4kTRB
Inlägg: 18289
Blev medlem: 16 augusti 2009, 19:04:48

Re: C++ frågor

Inlägg av 4kTRB »

Jag hade med #include <vector> för att testa med nån size grej men
då blev det massa gula varnings-symboler vid varje funktions-start
så jag tänkte att det är nog inget bra?
Användarvisningsbild
4kTRB
Inlägg: 18289
Blev medlem: 16 augusti 2009, 19:04:48

Re: C++ frågor

Inlägg av 4kTRB »

Nu läste jag det här...
1) std::vector is a sequence container that encapsulates dynamic size arrays.
2) std::pmr::vector is an alias template that uses a polymorphic allocator

The storage of the vector is handled automatically, being expanded and contracted as needed. Vectors usually occupy more space than static arrays, because more memory is allocated to handle future growth.
Det kanske är bättre att låta bli och så helt enkelt sätta STACKSIZEMAX till det värde jag
tror kommer bli den största stacken av de stack-objekt som skapas.
Varje objekt kommer om jag förstått det hela riktigt att ha en allocbuf[STACKSIZEMAX]
som låser det minnet. Tänkte mig att det är mindre bra på en Arduino med ont om minne.
Mr Andersson
Inlägg: 1394
Blev medlem: 29 januari 2011, 21:06:30
Ort: Lapplandet

Re: C++ frågor

Inlägg av Mr Andersson »

Ok men då går det inte deklarera static under private: ?
Jo. Men först måste du nog förklara vad du vill göra. Ska varje StackDouble-instans ha sin egen stack eller ska de dela på samma?

Standardcontainers, vector, list, map, etc, bör man nog undvika på plattformar med begränsat heap-minne.

Angående storlek så hade jag personligen valt templates istället för defines. Då kan man återanvända koden istället för att vara låst till en enda storlek eller typ.
Det kanske verkar konstigt att rekommendera templates till en som är ny med c++ men de är faktiskt inte så komplicerade som alla vill få det att låta. Se dem som en lite mer avancerad define till att börja med.
T.ex.

Kod: Markera allt

#include <iostream>

// templateargument
// överallt där TYPE finns, ersätt med den riktiga typen
// överallt där SIZE finns, ersätt med den riktiga storleken
template <typename TYPE, int SIZE>
class Stack {
public:
	void push(TYPE val) { if (current_ != end_) { *current_++ = val; } }
	TYPE pop() { if (current_ != start_) { return *--current_; } return 0; }
	size_t size() const { return SIZE; }
	size_t free() const { return end_ - current_; }
	size_t used() const { return size() - free(); }
private:
	TYPE start_[SIZE];
	const TYPE* end_ = start_+ SIZE;
	TYPE* current_ = start_;
};

int main() {
	using std::cout;
	using std::endl;

	// instansiera template
	Stack<double, 5> stack; // TYPE=double, SIZE=5

	cout << "stack size: " << stack.size() << endl;
	cout << "stack used: " << stack.used() << endl;
	cout << "stack free: " << stack.free() << endl << endl;

	stack.push(1);
	stack.push(2);
	stack.push(3);
	cout << "stack used: " << stack.used() << endl;
	cout << "stack free: " << stack.free() << endl << endl;
	stack.push(4);
	stack.push(5);
	stack.push(6);
	cout << "stack used: " << stack.used() << endl;
	cout << "stack free: " << stack.free() << endl << endl;

	cout << stack.pop() << endl;
	cout << stack.pop() << endl;
	cout << stack.pop() << endl;
	cout << stack.pop() << endl;
	cout << stack.pop() << endl;
	cout << "stack used: " << stack.used() << endl;
	cout << "stack free: " << stack.free() << endl << endl;
}

Kod: Markera allt

stack size: 5
stack used: 0
stack free: 5

stack used: 3
stack free: 2

stack used: 5
stack free: 0

5
4
3
2
1
stack used: 0
stack free: 5
[/size]
Användarvisningsbild
4kTRB
Inlägg: 18289
Blev medlem: 16 augusti 2009, 19:04:48

Re: C++ frågor

Inlägg av 4kTRB »

Jag ska titta på det men först förklara hur jag tror jag löst det
med dynamisk allokerad stack.

Jag använde new.

Jag vill att varje nytt objekt ska vara en stack och behålla sina värden.

Något blir hur som helst påverkat när ett nytt objekt skapas för som i exemplet
nedan så ska den första stacken jag skapar inte gå att fylla på med mer än
2 värden och det fungerar i första uppsättningen med push. Efter 3:dje push
så meddelas att stacken är full, helt ok.

Sedan skapar jag en ny stack som också beter sig helt ok.

Sedan återgår jag till första stacken men nu måste jag pusha 4ggr för att
få meddelande om att stacken är full, däremot när jag utför pop så verkar
det fungera helt riktigt.

Jag ser inte felet och jag testade att stacKSize var ok för första stacken i båda dessa fall.

Kod: Markera allt

//============================================================================
// Name        : MyFirstC++.cpp
// Author      : 4kTRB
// Version     :
// Copyright   : Your copyright notice
// Description : Hello World in C++, Ansi-style
//============================================================================

#include "StackDouble.h"
using namespace std;

int main() {
	StackDouble stackDouble_000(2);				// första stacken

	cout << "push" << NEWLINE;
	stackDouble_000.push(5.5);
	cout << "push" << NEWLINE;
	stackDouble_000.push(6.5);
	cout << "push" << NEWLINE;
	stackDouble_000.push(7.5);

	cout << "pop ";
	printf("%.2f\n", stackDouble_000.pop());
	cout << "pop ";
	printf("%.2f\n", stackDouble_000.pop());
	cout << "pop ";
	printf("%.2f\n", stackDouble_000.pop());

	cout << STRING << NEWLINE;

	StackDouble stackDouble_001(3);				// andra stacken

	cout << "push" << NEWLINE;
	stackDouble_001.push(15.5);
	cout << "push" << NEWLINE;
	stackDouble_001.push(16.5);
	cout << "push" << NEWLINE;
	stackDouble_001.push(17.5);

	cout << "pop ";
	printf("%.2f\n", stackDouble_001.pop());
	cout << "pop ";
	printf("%.2f\n", stackDouble_001.pop());
	cout << "pop ";
	printf("%.2f\n", stackDouble_001.pop());

	cout << STRING << NEWLINE;

	cout << "push" << NEWLINE;					// första stacken
	stackDouble_000.push(5.5);
	cout << "push" << NEWLINE;
	stackDouble_000.push(6.5);
	cout << "push" << NEWLINE;
	stackDouble_000.push(7.5);
	cout << "push" << NEWLINE;
	stackDouble_000.push(8.5);

	cout << "pop ";
	printf("%.2f\n", stackDouble_000.pop());
	cout << "pop ";
	printf("%.2f\n", stackDouble_000.pop());
	cout << "pop ";
	printf("%.2f\n", stackDouble_000.pop());
	cout << "pop ";
	printf("%.2f\n", stackDouble_000.pop());

	return 0;
}

/*
 * StackDouble.cpp
 *
 *  Created on: 4 feb. 2019
 *      Author: 4kTRB
 */

#include "StackDouble.h"
using namespace std;
//static double allocbuf[STACKSIZEMAX];
static double* allocbuf = NULL;
static double* stackTopPointer;
int stackSize;

StackDouble::StackDouble(int stacksize) {
	cout << "En instans av StackDouble" << NEWLINE;
	cout << STRING  << NEWLINE;
	stackSize = stacksize;
	allocbuf = new double[stacksize];
	for (int i=0; i<stacksize; i++) {
	    allocbuf[i] = 0;    				// Initialize all elements to zero.
	}
	stackTopPointer = allocbuf;				// peka på element noll i allocbuf
	bool b = allocdouble();					// allokera en stack om stacksize double
	if(!b){
		cout << "Allokering av stack överskred STACKSIZEMAX" << NEWLINE;
		cout << "STACKSIZEMAX = " << STACKSIZEMAX << NEWLINE;
		cout << STRING  << NEWLINE;
	}
}

/**
 * Allokera ett minnesområde för att lagra double.
 * Avancera pekaren stackTopPointer n steg för att peka på
 * start av stacken.
 * Returnera true om den allokerade stacken håller
 * sig inom ramen för STACKSIZEMAX annars returnera false
 */
bool StackDouble::allocdouble(){
	if ((allocbuf + STACKSIZEMAX - stackTopPointer) >= stackSize){
		stackTopPointer += stackSize;			// peka på stackens början
		return true;
	} else
		return false;
}

void StackDouble::push(double f){
	cout << "stackSize " << stackSize << NEWLINE;
	if(stackTopPointer > allocbuf){
		*stackTopPointer = f;
		stackTopPointer--;
	}
	else{
		cout << "Stacken är full" << NEWLINE;
	}
}

double StackDouble::pop(){
	if(stackTopPointer < (allocbuf + stackSize)){
		++stackTopPointer;
		return *stackTopPointer;
	}
	else{
		cout << "Stacken är tom så noll returneras ";
		return 0.0;
	}
}

/*
 * StackDouble.h
 *
 *  Created on: 4 feb. 2019
 *      Author: 4kTRB
 */
#pragma once

#define STACKSIZEMAX 20
#define NEWLINE '\n'
#define STRING "==========================================="
#include <iostream>

class StackDouble {

public:
	StackDouble(int);
	bool allocdouble();
	void push(double);
	double pop(void);
private:
	int stackSize;

};


En instans av StackDouble
===========================================
push
stackSize 2
push
stackSize 2
push
stackSize 2
Stacken är full
pop 6.50
pop 5.50
pop Stacken är tom så noll returneras 0.00
===========================================
En instans av StackDouble
===========================================
push
stackSize 3
push
stackSize 3
push
stackSize 3
pop 17.50
pop 16.50
pop 15.50
===========================================
push
stackSize 2
push
stackSize 2
push
stackSize 2
push
stackSize 2
Stacken är full
pop 7.50
pop 6.50
pop Stacken är tom så noll returneras 0.00
pop Stacken är tom så noll returneras 0.00

Zkronk
Inlägg: 1423
Blev medlem: 23 augusti 2005, 16:44:36
Ort: Uppsala

Re: C++ frågor

Inlägg av Zkronk »

För varje gång man anropar new och allokerar minne på heapen måste man komma ihåg att anropa delete sen när man är klar.
I det är fallet vore det nog lämpligt i StackDouble's destruktor.

Här där programmet bara kör en kort stund och sen termineras så är det väl inte hela världen, men det är en god programmeringsvana :)
Användarvisningsbild
4kTRB
Inlägg: 18289
Blev medlem: 16 augusti 2009, 19:04:48

Re: C++ frågor

Inlägg av 4kTRB »

Det kan verka vettigt ja.

Men det påverkar väl inte det lite underliga felet jag får ovan?

Är det något fel med testet i push-funktionen som gör att utskriften om "stack full"
kommer först efter 4:de push ?

Om jag inte skapar ytterligare en ny stack, alltså tar bort
StackDouble stackDouble_001(3);,
och utför samma sekvens med push med stackDouble_000
en andra gång som ovan då funkar det helt ok.

Kod: Markera allt

void StackDouble::push(double f){
   cout << "stackSize " << stackSize << NEWLINE;
   if(stackTopPointer > allocbuf){
      *stackTopPointer = f;
      stackTopPointer--;
   }
   else{
      cout << "Stacken är full" << NEWLINE;
   }
}
Användarvisningsbild
4kTRB
Inlägg: 18289
Blev medlem: 16 augusti 2009, 19:04:48

Re: C++ frågor

Inlägg av 4kTRB »

Det som verkar hända ser jag nu,
när jag skapar ett nytt objekt
så använder gamla objektet den nya stacken som nya objektet skapar.

För om jag skapar
StackDouble stackDouble_000(2); och StackDouble stackDouble_001(2);

så ger 3 push med stackDouble_000 stack full och sedan
samma resultat på nytt medans om jag skapar

StackDouble stackDouble_000(2); och StackDouble stackDouble_001(3);
så måste det till 4 push med stackDouble_000 andra gången.

Det var ju inte riktigt meningen.
Användarvisningsbild
4kTRB
Inlägg: 18289
Blev medlem: 16 augusti 2009, 19:04:48

Re: C++ frågor

Inlägg av 4kTRB »

Testade med static och private men
en ny instans skapar en stack på den
gamla i alla fall.
:(

Kod: Markera allt

/*
 * StackDouble.h
 *
 *  Created on: 4 feb. 2019
 *      Author: 4kTRB
 */
#pragma once

#define STACKSIZEMAX 20
#define NEWLINE '\n'
#define STRING "==========================================="
#include <iostream>

class StackDouble {

public:
	StackDouble(int);
	bool allocdouble();
	void push(double);
	double pop(void);
	void FreeAlloc(void);
private:
	int stackSize;
	static double* allocbuf;
	static double* stackTopPointer;
};

/*
 * StackDouble.cpp
 *
 *  Created on: 4 feb. 2019
 *      Author: 4kTRB
 */

#include "StackDouble.h"
using namespace std;
//static double allocbuf[STACKSIZEMAX];
//static double* allocbuf = NULL;
int stackSize;
double* StackDouble::allocbuf = NULL;
double* StackDouble::stackTopPointer = NULL;
henkebenke
Inlägg: 515
Blev medlem: 31 maj 2003, 10:42:37
Ort: Helsingborg

Re: C++ frågor

Inlägg av henkebenke »

Är det inte static-deklarationen av allocbuf och stackTopPointer som är problemet? En static class-member hänger väl med alla instanser av objektet?
Mr Andersson
Inlägg: 1394
Blev medlem: 29 januari 2011, 21:06:30
Ort: Lapplandet

Re: C++ frågor

Inlägg av Mr Andersson »

Ja det gör det. Ta bort static.
Zkronk
Inlägg: 1423
Blev medlem: 23 augusti 2005, 16:44:36
Ort: Uppsala

Re: C++ frågor

Inlägg av Zkronk »

Sorry för att jag har skrivit om din kod en hel del, men jag har gjort på ett annat sätt som kanske är intressant?
Ett problem som kvarstår är att pop-funktionen returnerar 0.0 när det är tomt i stacken...

Kod: Markera allt

//============================================================================
// Name        : MyFirstC++.cpp
// Author      : 4kTRB
// Version     :
// Copyright   : Your copyright notice
// Description : Hello World in C++, Ansi-style
//============================================================================

#include "StackDouble.h"
using namespace std;

int main() {
   StackDouble stackDouble_000(2);            // första stacken

   cout << "push" << endl;
   stackDouble_000.push(5.5);
   cout << "push" << endl;
   stackDouble_000.push(6.5);
   cout << "push" << endl;
   stackDouble_000.push(7.5);

   cout << "pop ";
   cout << stackDouble_000.pop() << endl;
   cout << "pop ";
   cout << stackDouble_000.pop() << endl;
   cout << "pop ";
   cout << stackDouble_000.pop() << endl;

   cout << STRING << endl;

   StackDouble stackDouble_001(3);            // andra stacken

   cout << "push" << endl;
   stackDouble_001.push(15.5);
   cout << "push" << endl;
   stackDouble_001.push(16.5);
   cout << "push" << endl;
   stackDouble_001.push(17.5);

   cout << "pop ";
   cout << stackDouble_001.pop() << endl;
   cout << "pop ";
   cout << stackDouble_001.pop() << endl;
   cout << "pop ";
   cout << stackDouble_001.pop() << endl;

   cout << STRING << endl;


   return 0;
}

Kod: Markera allt

/*
 * StackDouble.h
 *
 *  Created on: 4 feb. 2019
 *      Author: 4kTRB
 */
#pragma once

#define STRING "==========================================="
#include <iostream>

class StackDouble {

public:
   StackDouble(int stackcapacity);
   ~StackDouble();
   void push(double number);
   double pop(void);

private:
   int stackSize;
   int stackCapacity;
   double* stack;
};

Kod: Markera allt

/*
 * StackDouble.cpp
 *
 *  Created on: 4 feb. 2019
 *      Author: 4kTRB
 */

#include "StackDouble.h"
using namespace std;

StackDouble::StackDouble(int stackcapacity) : stackCapacity(stackcapacity), stackSize(0) 
{
   stack = new double[stackCapacity];

   cout << "En instans av StackDouble har skapats." << endl;
   cout << STRING  << endl;
}

StackDouble::~StackDouble()
{
    delete stack;
    cout << "En instans av StackDouble har tagits bort." << endl; 
}

void StackDouble::push(double number){
   cout << "stackSize " << stackSize << endl;

   if(stackSize < stackCapacity)
   {
      stack[stackSize++] = number;
   }
   else
   {
      cout << "Stacken är full" << endl;
   }
}

double StackDouble::pop(){
   if(stackSize > 0)
   {
      return stack[--stackSize];
   }
   else
   {
      cout << "Stacken är tom så noll returneras " << endl;
      return 0.0;
   }
}
Användarvisningsbild
4kTRB
Inlägg: 18289
Blev medlem: 16 augusti 2009, 19:04:48

Re: C++ frågor

Inlägg av 4kTRB »

Det där ser riktigt bra ut.
Jag ser inga stora skillnader på den variant jag försöker med
mer än att stackTopPointer verkar vara en bov i dramat.
Jag jobbar mig ned mot allocbuf[0] vid push, det är tvärt om men
borde fungera.

Den här koden fungerar helt enkelt inte som var avsikten...trots att jag tar bort static.

Kod: Markera allt

*
 * StackDouble.h
 *
 *  Created on: 4 feb. 2019
 *      Author: 4kTRB
 */
#pragma once
#define STACKSIZEMAX 20
#define NEWLINE '\n'
#define STRING "==========================================="
#include <iostream>

class StackDouble {

public:
	StackDouble(int stacksize);
	void push(double f);
	double pop(void);

private:
	void FreeAlloc(void);
	bool allocdouble();
	double* allocbuf;
	double* stackTopPointer;
	int stackSize;
};

Kod: Markera allt

/*
 * StackDouble.cpp
 *
 *  Created on: 4 feb. 2019
 *      Author: 4kTRB
 */

#include "StackDouble.h"
using namespace std;
//static double allocbuf[STACKSIZEMAX];
//static double* allocbuf = NULL;

StackDouble::StackDouble(int stacksize) {
	cout << "En instans av StackDouble" << NEWLINE;
	cout << STRING  << NEWLINE;

	stackSize = stacksize;
	allocbuf = new double[stacksize];
	for (int i=0; i<stacksize; i++) {
		allocbuf[i] = 0;    				// Initialize all elements to zero.
	}
	stackTopPointer = allocbuf;				// peka på element noll i allocbuf
	//	stackTopPointer = &allocbuf[0];		// fungerar också
	bool b = allocdouble();					// allokera en stack om stacksize double
	if(!b){
		cout << "Allokering av stack överskred STACKSIZEMAX" << NEWLINE;
		cout << "STACKSIZEMAX = " << STACKSIZEMAX << NEWLINE;
		cout << STRING  << NEWLINE;
	}
}
/**
 * Allokera ett minnesområde för att lagra double.
 * Avancera pekaren stackTopPointer n steg för att peka på
 * start av stacken.
 * Returnera true om den allokerade stacken håller
 * sig inom ramen för STACKSIZEMAX annars returnera false
 */
bool StackDouble::allocdouble(){
	if ((allocbuf + STACKSIZEMAX - stackTopPointer) >= stackSize){
		stackTopPointer += stackSize;			// peka på stackens början
		return true;
	} else
		return false;
}

void StackDouble::push(double f){
	if(stackTopPointer > allocbuf){
		*stackTopPointer = f;
		stackTopPointer--;
	}
	else{
		cout << "Stacken är full" << NEWLINE;
	}
}

double StackDouble::pop(){
	if(stackTopPointer < (allocbuf + stackSize)){
		++stackTopPointer;
		return *stackTopPointer;
	}
	else{
		cout << "Stacken är tom så noll returneras ";
		return 0.0;
	}
}
void StackDouble::FreeAlloc(){
	delete [] allocbuf;  				// Free memory allocated for the a array.
	allocbuf = NULL;     				// Be sure the deallocated memory isn't used.
	stackTopPointer = NULL;
}

Skriv svar