Forum: PC-Programmierung C++, festellen ob operator new nutzbar verfügbar ist?


von CppBert3 (Gast)


Angehängte Dateien:

Lesenswert?

Für eine Art Komponenten-Konzept ala COM (+ abstrakte Schnittstellen 
über DLL Grenzen mit anderen CRTs).
Um meine Architektur noch "benutzungssicherer" zu machen versuche ich 
gerade:

1. zu verhindern das meine Klassen direkt auf dem Stack oder Heap 
erzeugbar sind
2. zur Kompilierzeit zu prüfen ob die Klasse auch diesen Anforderungen 
entspricht
3. einen Weg zu finden wie das "Konzept" z.B. über Ableitung leichter 
auf viele Klassen angwendet werden kann

siehe Anhang oder zum Online kompilieren: 
https://onlinegdb.com/ByCTre1qE

von Dr. Sommer (Gast)


Lesenswert?

CppBert3 schrieb:
> 1. zu verhindern das meine Klassen direkt auf dem Stack oder Heap
> erzeugbar sind

Wo denn sonst, ausschließlich als globale/statische Variable? Das geht 
aber nicht mit Factory-methoden, und der Konstruktor muss verfügbar 
sein. Wenn er das ist, kann aber auch jemand die Klasse als 
Member-Variable in eine andere Klasse packen, welche dann auf dem Heap 
oder Stack ist.

Was ist der Vorteil daran, wenn Klassen nicht normal allokiert werden 
können? Mehr "new" Aufrufe, mehr Zeit fürs Anlegen, mehr 
Zeiger-Dereferenzierung, fragmentierter Speicher, schlechteres 
Cache-Verhalten?

von Dr. Sommer (Gast)


Lesenswert?

PS: einer der Vorteile von C++ ist ja gerade, dass man eine komplexe 
Objekt-Struktur mit nur einem "new" Aufruf anlegen kann, sodass die dann 
in einem zusammenhängenden Block Speicher ist. Wenn man das nicht nutzt, 
jede Instanz separat anlegt, auf alles per Pointer zugreift, kann man 
auch direkt Java oder CLR nehmen. Die sind wenigstens auf dieses Modell 
ausgelegt und können das teilweise besser optimieren als C++.

von Fred (Gast)


Lesenswert?

Solche Experimente resultieren meist aus ein paar UML-Vorlesungen zu 
viel und ein paar C++-Büchern zu wenig. C++ ist eben trotz seiner vielen 
Möglichkeiten nicht der persönliche Sprachbaukasten und nicht jedes 
Konstrukt, was auf dem Papier schön aussieht kann umgesetzt werden.

von CppBert3 (Gast)


Lesenswert?

@Dr. Sommer

"Wo denn sonst, ausschließlich als globale/statische Variable? Das geht
aber nicht mit Factory-methoden"

dafür sind die statischen New Methoden, aber wie gesagt will ich die 
Entwickler nur unterstützen Klassen zu machen die weniger 
"problematisch" sind

und @Fred
ich mag kein UML, es gibt wenige Vorlesungen die sich lohnen und die 
meisten C++ Bücher sind ihr Geld leider nicht Wert

kurz um:

Das ist mir alles 100% klar und ich mag das Konzept auch nicht - meine 
Ziel sind normalerweise viel RAII, so viel wie moegliche Stack, wenig 
Heap, const so weit das Auge reicht, Kompiletime-Safe, ...

Aber dieses COM-like-Konzept dem ich hier ausgesetzt bin (Interfaces, 
AddRef/Release/C-Schnittstelle usw.) aus DLLs (die Teilweise sogar nicht 
in C/C++ geschrieben sind) zu erzeugen und sharen mit unterschiedlichen 
CRTs (Heaps) erzwingt blöde Konstruktionen - das einzige was ich 
erreichen will ist es dennoch so gut wie möglich zu vermeiden das die 
Entwickler es falsch machen können

Die Prüfung ob eine Komponenten nicht default-konstruiert werden kann 
schaffe ich schon weil alle C++-Entwickler gezwungen sind ihre 
Implementationen durch ein Variadic-Template bei einer Factory "an zu 
melden" - alles was dort immer noch default-konstruierbar ist führt zu 
Kompilierfehlern - aber auf dem Heap anlegen kann mann dann immer noch, 
die statischen New-Methoden sind auch nur ein Beispiel - ich habe 
abstrakte Konstruktoren die ich per Template-Mechanismus komplett zur 
Kompilezeit absicher

aber ich will verhindern das jemand new/delete benutzt - und möchte 
nicht das jeder das immer wieder private "implementieren" muss

oder ich prüfe eben in meiner Factory ob zur Kompilezeit die new/delete 
operatoren noch vorhanden sind - aber wie das geht ist mir auch nicht 
klar

von Dr. Sommer (Gast)


Lesenswert?

CppBert3 schrieb:
> dafür sind die statischen New Methoden

Und wo legen die die Instanz ab, wenn nicht auf dem Heap?

CppBert3 schrieb:
> aber auf dem Heap anlegen kann mann dann immer noch,

Wie denn, wenn der Konstruktor "private" ist...

Normalerweise macht man den Konstruktor private, dann geht nur noch die 
Factory-Methode. Die operatoren "new" und "delete" fasst man dabei nicht 
an.

von BobbyX (Gast)


Lesenswert?

Fred schrieb:
> Solche Experimente resultieren meist aus ein paar UML-Vorlesungen
> zu
> viel und ein paar C++-Büchern zu wenig. C++ ist eben trotz seiner vielen
> Möglichkeiten nicht der persönliche Sprachbaukasten und nicht jedes
> Konstrukt, was auf dem Papier schön aussieht kann umgesetzt werden.

Das schlimme ist, dass solche Experimente bei der Realisierung von 
Software-Projekten tatsächlich angewandt werden. Und oft von ihren 
Schöpfern ans das tollste überhaupt angepriesen werden. Wenn sie auf 
Projektmanagement ohne Ahnung treffen dann nimmt der Wahnsinn seinen 
Lauf... Statt sich auf die eigentliche Aufgabe zu konzentrieren wird 
unheimlich viel Aufwand betrieben das ach so tolle Konzept umzusetzen.

Am Ende hat man ein architektonisches Monster mit dem man sich jahrelang 
herumschlagen muss.

Deswegen steht bei mir das KISS Prinzip an der obersten Stelle....

von Bert3 (Gast)


Lesenswert?

Dr. Sommer schrieb:
> CppBert3 schrieb:
>> dafür sind die statischen New Methoden
>
> Und wo legen die die Instanz ab, wenn nicht auf dem Heap?
>
> CppBert3 schrieb:
>> aber auf dem Heap anlegen kann mann dann immer noch,
>
> Wie denn, wenn der Konstruktor "private" ist...
>
> Normalerweise macht man den Konstruktor private, dann geht nur noch die
> Factory-Methode. Die operatoren "new" und "delete" fasst man dabei nicht
> an.

Ich will nur nicht new und delete direkt erlauben - oder das 
vorhandensein erkennen - weil new nur versteckt genutzt wird und delete 
auf diesen Objekten ausserhalb der DLL nicht funktioniert weil es in 
meinem Szenario unterschiedliche Heaps sind

Alles andere was ihr erklärt ist mir absolut klar - ich wuerde das 
gleiche schreiben wie ihr

von Bert3 (Gast)


Lesenswert?

Koennte man mit dem CRTPattern die private new/delete operator per 
Ableitung einbringen?

von Dr. Sommer (Gast)


Lesenswert?

Bert3 schrieb:
> Ich will nur nicht new und delete direkt erlauben - oder das
> vorhandensein erkennen

Aber statische oder -Stack-Allokation soll doch gehen? Aber es hieß doch

CppBert3 schrieb:
> 1. zu verhindern das meine Klassen direkt auf dem Stack oder Heap
> erzeugbar sind

Beschreibe noch mal klar und eindeutig, was gehen soll und was nicht.

Btw, was ist eigentlich das Problem wenn eine Klasse auf dem "falschen" 
Heap ist - Zeiger darauf funktionieren ja trotzdem.

von M.K. B. (mkbit)


Lesenswert?

Ich hab den Eindruck, du versuchst eine sinnvolle Ausbildung der 
Entwickler, Coding Guidelines und Reviews mit der Sprache zu erschlagen.

Mir kommen zwei Aussagen von dir komisch vor.

Default Konstruktion willst du verbieten. Das man das für eine Klasse 
macht ist sinnvoll, aber warum darf keine Klasse das machen. Oder willst 
du vielleicht einen private Konstruktor, der immer nur über eine Factory 
aufgerufen wird.

Kein new/delete. Damit müsstest du eigentlich die Std lib abschalten, 
weil z.B. std:string std:vector ohne heap nicht funktionieren.

von Oliver S. (oliverso)


Lesenswert?

Bert3 schrieb:
> Ich will nur nicht new und delete direkt erlauben - oder das
> vorhandensein erkennen - weil new nur versteckt genutzt wird und delete
> auf diesen Objekten ausserhalb der DLL nicht funktioniert weil es in
> meinem Szenario unterschiedliche Heaps sind

Dan nimm halt eine Factory, die einen Shared_ptr mit passendem Deleter 
liefert.

Oliver

von Dr. Sommer (Gast)


Lesenswert?

BobbyX schrieb:
> Das schlimme ist, dass solche Experimente bei der Realisierung von
> Software-Projekten tatsächlich angewandt werden.

Wenn man nicht experimentiert, gibts auch keine Innovation. Manchmal 
muss man auch was neues ausprobieren. Ob sich ein Paradigma bewährt, 
kann man am Besten in einem Praxistest feststellen. Allerdings sollte es 
die Möglichkeit geben, einige Erfahrungen zu sammeln und dann eine 
erneuerte und wahrscheinlich nicht-abwärtskompatible Version 2.0 zu 
erstellen, anstatt sich ewig an den ersten Entwurf zu binden.

von Bert3 (Gast)


Lesenswert?

Dr. Sommer schrieb:
> Bert3 schrieb:
>> Ich will nur nicht new und delete direkt erlauben - oder das
>> vorhandensein erkennen
>
> Aber statische oder -Stack-Allokation soll doch gehen? Aber es hieß doch
>
> CppBert3 schrieb:
>> 1. zu verhindern das meine Klassen direkt auf dem Stack oder Heap
>> erzeugbar sind
>
> Beschreibe noch mal klar und eindeutig, was gehen soll und was nicht.
>
> Btw, was ist eigentlich das Problem wenn eine Klasse auf dem "falschen"
> Heap ist - Zeiger darauf funktionieren

In meinem Beispiel geht nicht auf dem stack und nicht direkt auf dem 
heap

Zeiger drauf funktioniert - aber delete geht defitiv nicht

von Bert3 (Gast)


Lesenswert?

M.K. B. schrieb:
> Ich hab den Eindruck, du versuchst eine sinnvolle Ausbildung der
> Entwickler, Coding Guidelines und Reviews mit der Sprache zu erschlagen.
>
> Mir kommen zwei Aussagen von dir komisch vor.
>
> Default Konstruktion willst du verbieten. Das man das für eine Klasse
> macht ist sinnvoll, aber warum darf keine Klasse das machen. Oder willst
> du vielleicht einen private Konstruktor, der immer nur über eine Factory
> aufgerufen wird.
>
> Kein new/delete. Damit müsstest du eigentlich die Std lib abschalten,
> weil z.B. std:string std:vector ohne heap nicht funktionieren.

Es geht nicht um alle Klassen sonder nur um eine spezielle Gruppe alles 
andere waere auch echt zu verrückt

Ich will jegliche direkte Konstruktion verhindern
Deswegen sind die alle ctors privat in meinem Beispiel, ja es wird eine 
Factory genutzt

von Bert3 (Gast)


Lesenswert?

Oliver S. schrieb:
> Bert3 schrieb:
>> Ich will nur nicht new und delete direkt erlauben - oder das
>> vorhandensein erkennen - weil new nur versteckt genutzt wird und delete
>> auf diesen Objekten ausserhalb der DLL nicht funktioniert weil es in
>> meinem Szenario unterschiedliche Heaps sind
>
> Dan nimm halt eine Factory, die einen Shared_ptr mit passendem Deleter
> liefert.
>
> Oliver

Das mache ich zusaetzlich auf der DLL Nutzungsseite

von Fred (Gast)


Lesenswert?

Dr. Sommer schrieb:
> Wenn man nicht experimentiert, gibts auch keine Innovation. Manchmal
> muss man auch was neues ausprobieren. Ob sich ein Paradigma bewährt,
> kann man am Besten in einem Praxistest feststellen.

Das stimmt zwar grundsätzlich, aber eben nur innerhalb sinnvoller 
Grenzen. Es ist auch keine Innovation wenn ich ein fünftes Rad an meinen 
Benz schraube. Wenn der OP dieses Konzept in seiner eigenen neuen 
Sprache umsetzen wollen würde, spräche erst einmal nichts dagegen. In 
einer existierenden Sprache aber grundlegende Konzepte umbiegen zu 
wollen, ergibt keinen Sinn.

Vielleicht ist es aber notwendig, mit sowas ein paar Mal zu Hause 
gescheitert zu sein, um nicht auf die Idee zu kommen, Andere auf der 
Arbeit damit zu quälen.

von Dr. Sommer (Gast)


Lesenswert?

Fred schrieb:
> In
> einer existierenden Sprache aber grundlegende Konzepte umbiegen zu
> wollen, ergibt keinen Sinn.

Man kann durchaus versuchen, die Vorteile einer Sprache mit einem 
bestimmten Paradigma zu verbinden. z.B. könnte man das Aktor-Modell in 
C++ implementieren, um die Performance-Vorteile und Embedded-Eignung von 
C++ zu nutzen, anstatt ausschließlich die "Aktor-Sprache" Erlang zu 
nutzen oder gar eine komplett neue Sprache zu entwickeln.

Bert3 schrieb:
> Ich will jegliche direkte Konstruktion verhindern

Ich glaube keiner weiß was du genau willst. Du widersprichst dir selbst 
und deine Wünsche sind wirr.

Sag doch mal welches der folgenden Beispiele ok ist und welches nicht:
1.
1
int main () {
2
  ClassA* a = new ClassA (42);
3
  delete a;
4
}
2.
1
int main () {
2
  ClassA a (42);
3
}
3.
1
ClassA a (42);
2
int main () {
3
}
4.
1
struct X {
2
  ClassA a;
3
  X () : a (42) {}
4
}
5
X x;
6
int main () {}
5.
1
struct X {
2
  ClassA a;
3
  X () : a (42) {}
4
}
5
int main () {
6
  X x;
7
}
6.
1
struct X {
2
  ClassA a;
3
  X () : a (42) {}
4
}
5
int main () {
6
  X* x = new X ();
7
  delete x;
8
}
7.
1
int main () {
2
  std::unique_ptr<ClassA> p (new ClassA (42));
3
}
8.
1
int main () {
2
  std::unique_ptr<ClassA, ClassA::Deleter> p (new ClassA (42), ClassA::deleter);
3
}
Wem fallen noch mehr ein...?

von Bert3 (Gast)


Lesenswert?

Ich verstehe deine Frage nicht, reicht das das angehaengte Beispiel aus 
dem 1. Post nicht? Was mit dieser Beispielklasse nicht geht will ich 
verhindern oder zur Kompilzeit gezielt pruefen das sie sich so verhalten

Dieses Beispiel ist maximal reduziert, meine echter Code darum ist um 
ein vielfaches  groesser

Es geht mir wie gesagt nur darum das "Konzept" der direkten new und 
deletebarkeit zu enforcen, am besten per Ableitung oder CRTP

von Bert3 (Gast)


Lesenswert?

1-6 will ich nicht - wie in meinem Beispiel
7-8 mache ich schon

von Dr. Sommer (Gast)


Lesenswert?

Bert3 schrieb:
> Ich verstehe deine Frage nicht, reicht das das angehaengte Beispiel aus
> dem 1. Post nicht?

Nein. Es ist komplett unklar was du willst.

Bert3 schrieb:
> Es geht mir wie gesagt nur darum das "Konzept" der direkten new und
> deletebarkeit zu enforcen, am besten per Ableitung oder CRTP

Ja, aber dazu muss man wissen was du willst.

Bert3 schrieb:
> 1-6 will ich nicht - wie in meinem Beispiel
> 7-8 mache ich schon

Das geht nicht. Wenn 7. erlaubt ist lässt sich 1. nicht verhindern - 
beide Male wird "new" im selben Kontext aufgerufen.

von Fred (Gast)


Lesenswert?

Dr. Sommer schrieb:
> Ja, aber dazu muss man wissen was du willst.

Der OP will die grundlegenden Regeln der Sprache umschreiben.

von M.K. B. (mkbit)


Lesenswert?

Bert3 schrieb:
> Es geht mir wie gesagt nur darum das "Konzept" der direkten new und
> deletebarkeit zu enforcen, am besten per Ableitung oder CRTP

New und Delete kannst du nicht direkt verbieten, außer du hast ein 
Bibliothek oder Compileroption, die new/delete und malloc/free nicht zur 
Verfügung stellt. Das gibt dann Linkerfehler.

Ansonsten kann in C++ nur die öffentliche Konstruktion/Dekonstruktion 
verhindert werden. Damit bleiben dann aber nur eine Factory. die mit 
RAII arbeiten. Für Factoryfunctions muss das Objekt kopierbar sein, 
damit es ohne Heap in einem Scope außerhalb der Factoryfunction leben 
kann. Damit kann aber dann der Destruktor nicht private sein, weil es ja 
sonst keiner mehr zerstören kann.

Ansonsten hätte ich noch folgende Frage:
Welches konkrete Problem, bitte mit Beispiel, möchtest du lösen. Bzw. 
welche falsche Verwendung macht dir Probleme und warum.

von CppBert3 (Gast)


Lesenswert?

Dr. Sommer schrieb:
> Bert3 schrieb:
>> Es geht mir wie gesagt nur darum das "Konzept" der direkten new und
>> deletebarkeit zu enforcen, am besten per Ableitung oder CRTP
>
> Ja, aber dazu muss man wissen was du willst.

ich will ein Konzept für einen User-Klasse enforcen welche nicht weiter 
abgeleitet wird und ein spezielles Konstruktionsprinzip nutzt - diesen 
Umfangreichen Code will und kann ich aber nicht zeigen

Ich will nur das "Konzept" das die new/delete Operatoren privat und 
(wenn es irgendwie geht) das alle Konstruktoren privat sind - falls das 
nicht moeglich ist würde es mir auch reichen zur Kompilezeit zu prüfen 
ob das Konzept erfüllt ist - also kein new/delete Operator Zugreifbar, 
kein oeffentlicher Konstruktor - alles andere sind technische Details 
die ich hier gar nicht besprechen wollte (oder dachte nicht zu brauchen)

so in der Art wie:

https://www.boost.org/doc/libs/1_69_0/libs/core/doc/html/core/noncopyable.html

aber eben only_private_heapable und only_private_constructible - damit 
ich eine spezielle Sorte von Komponenten-Klasse leicht damit ausstatten 
kann

mit würde schon ein trait oder sowas reichen mit dem ich auf die 
new/delete operatoren prüfen kann

> Bert3 schrieb:
>> 1-6 will ich nicht - wie in meinem Beispiel
>> 7-8 mache ich schon

Ich haben einen speziellen SharedPointer der aus der Factory erzeugt 
wird welche private new/delete nutzen darf/kann

von CppBert3 (Gast)


Lesenswert?

M.K. B. schrieb:
> New und Delete kannst du nicht direkt verbieten, außer du hast ein
> Bibliothek oder Compileroption, die new/delete und malloc/free nicht zur
> Verfügung stellt. Das gibt dann Linkerfehler.

Es geht mir nur um die New/Delete-Operatoren spezieller Klassen - wie in 
meinem Beispiel gezeigt

von M.K. B. (mkbit)


Lesenswert?

CppBert3 schrieb:
> Es geht mir nur um die New/Delete-Operatoren spezieller Klassen - wie in
> meinem Beispiel gezeigt

Ich habe mich vielleicht etwas ungenau ausgedrückt. Die Klasse selbst 
hat nichts mit new/delete zu tun.
Die etwas vereinfachte Darstellung, was beim anlegen eine Objektes 
passiert:

Heap new T(a,b,c):
- p = malloc(sizeof(T))
- ((T*)p)->ctor(a,b,c)
- return (T*)p

Stack T(a,b,c):
- p = stack
- stack = stack + sizeof(T)
- ((T*)p)->ctor(a,b,c)

Wie du siehst sieht das Objekt selbst nicht, wo der Speicher herkommt 
und kann damit auch nicht zwischen Heap/Stack unterscheiden.

von Fred (Gast)


Lesenswert?

Tja da wirst du wohl deinen eigenen Preprocessor brauchen.

von CppBert3 (Gast)


Lesenswert?

M.K. B. schrieb:
> Wie du siehst sieht das Objekt selbst nicht, wo der Speicher herkommt
> und kann damit auch nicht zwischen Heap/Stack unterscheiden.

wer sagt das ich das unterscheiden möchte? - ich moechte nur verhindern 
das man direct new und delete auf speziellen Klassen aufrufen kann - 
oder deren Konstruktoren für direkte Erzeugung auf dem Stack aufrufen 
kann

Versuch doch mal meine ClassA auf dem Stack oder Heap an zu legen
1
#include <cstddef>
2
3
class ClassA
4
{
5
private:
6
  // keine Stack-Konstruction mehr moeglich
7
  ClassA();
8
  ClassA(int a) {}
9
  ClassA(int a, float b) {}
10
11
  // keine direkte Heap-Konstruction mehr moeglich
12
  void* operator new(std::size_t size){ return ::operator new(size); }
13
  // kein Heap delete mehr moeglich
14
  void operator delete(void* object) { ::operator delete(object); }
15
  //die Array-Varianten fehlen noch...
16
17
public: // Das "Interface" für meine Factory
18
  // mein "new" aka verstecktes new+ctor nutzen
19
  static ClassA* New(int a) { return new ClassA(a); }
20
  static ClassA* New(int a, float b) { return new ClassA(a, b); }
21
22
  // mein "delete"
23
  void Delete() /*override*/ { delete this; }
24
};
25
26
int main()
27
{
28
  // 1. scheint damit erfüllt
29
  //ClassA t; // kompiliert nicht - OK
30
  //ClassA t(1,2.0); // kompiliert nicht - OK
31
  //ClassA* t = new ClassA(); // kompiliert nicht - OK
32
  //ClassA* t = new ClassA(1,2.0); // kompiliert nicht - OK
33
34
  //ClassA* x = nullptr;
35
  //delete x; // kompiliert nicht - OK
36
37
  return 0;
38
}

und dieses Konzept will ich per Ableitung, CRTP oder sonsteiner Technik 
in meine speziellen (viele) Klassen bringen oder wenigstens per 
Kompilezeit prüfen können ob sie nicht auf dem Stack oder Heap erzeugbau 
sind oder Heap-delete erlauben (per traits, whatever, ...)

von CppBert3 (Gast)


Lesenswert?

Kurz: Ich will Heap-Anlage über meine Factory erzwingen und die 
Standard-Wege (new/delete/on Stack) verhindern

von Heiko L. (zer0)


Lesenswert?

Interfaces sind alleine deshalb schon nicht normal konstruierbar, weil 
sie abstrakt sind. Realisierungen sind keine Schnittstellen, also auch 
nichts, womit man zu tun hätte, wenn man nicht gerade eine 
implementiert.

von Dr. Sommer (Gast)


Angehängte Dateien:

Lesenswert?

CppBert3 schrieb:
> Kurz: Ich will Heap-Anlage über meine Factory erzwingen und die
> Standard-Wege (new/delete/on Stack) verhindern

Du willst einfach die komplette externe Konstruktion verhindern, völlig 
unabhängig vom Speicherort. Die Hinweise auf "Heap" / "Stack" sind nur 
Nebelkerzen.

Es ist nicht 100% realisierbar. "test1.cc" im Anhang kommt nahe. 
UserClass könnte aber immer noch irgendeinen public-Konstruktor 
definieren, dessen Existenz sich nicht per static_assert prüfen lässt. 
Die Existenz des Destruktors lässt sich aber prüfen, da es davon ja nur 
einen gibt.

Als fiesen Hack könnte man zur Laufzeit prüfen, ob Base::Base aus dem 
Kontext der "create" Funktion aufgerufen wurde (siehe test2.cc).

von M.K. B. (mkbit)


Lesenswert?

CppBert3 schrieb:
> Kurz: Ich will Heap-Anlage über meine Factory erzwingen und die
> Standard-Wege (new/delete/on Stack) verhindern

Also willst du doch pro Klasse unterscheiden, ob diese auf dem Heap oder 
Stack angelegt werden kann. In deinem Post davor stellst du aber das in 
Frage.
Was willst du nun? Sortiere mal deine Gedanken.

Und wie schon gesagt. Man kann dir helfen, wenn man wüsste, was du 
vorhast. Also entweder ein konkretes Beispiel oder halt keine Lösung. 
Nicht mein Problem.

von Dr. Sommer (Gast)


Lesenswert?

Bert3 schrieb:
> Zeiger drauf funktioniert - aber delete geht defitiv nicht

PS: Wenn die Destruktoren virtuell sind, erfolgt das Löschen in einem 
unsichtbaren Hilfs-Destruktor, d.h. in der DLL und damit auf dem 
richtigen Heap! Das nennt sich "Deleting Destructor":

https://eli.thegreenplace.net/2015/c-deleting-destructors-and-virtual-operator-delete/

Was ist an meinen Beispiel-Fällen 2-5 eigentlich das Problem? Die 
Objekte landen gar nicht auf irgendeinem Heap und es wird nie "new" oder 
"delete" aufgerufen, schon gar nicht von einem falschen Heap.

Bei Fall 1 und 6-8 landen die Instanzen zwar auf dem "falschen" Heap, 
aber da "delete" ebenfalls auf eben diesem falschen Heap aufgerufen 
wird, ergibt sich kein Problem. Probleme entstehen nur wenn man eine 
Instanz in einem Modul (DLL oder Anwendung) erstellt und in einem 
anderen wieder löscht. Das sollte man sowieso niemals tun; der Code 
(typ. eine Klasse) welcher die Allokation besorgt sollte sie auch wieder 
freigeben. Alles andere wird unübersichtlich.

Wenn man einen std::unique_ptr oder std::shared_ptr mit einem Deleter 
verwendet, welcher im selben Modul wie die Allokation definiert ist, 
wird es auch immer richtig aufgerufen - selbst wenn man den Smart 
Pointer an ein anderes Modul übergibt.

von Rasputin (Gast)


Lesenswert?

Ich glaube, ich verstehe, was du möchtest. Das Passkey-Idiom könnte 
deine Lösung sein:
https://arne-mertz.de/2016/10/passkey-idiom/

von CppBert3 (Gast)


Lesenswert?

Dr. Sommer schrieb:
> Probleme entstehen nur wenn man eine
> Instanz in einem Modul (DLL oder Anwendung) erstellt und in einem
> anderen wieder löscht. Das sollte man sowieso niemals tun; der Code
> (typ. eine Klasse) welcher die Allokation besorgt sollte sie auch wieder
> freigeben. Alles andere wird unübersichtlich.

Genau das passiert in meinem System aber (es werden Objekte in 
verschiedenen) DLL erzeugt und von anderen DLLs ge-shared/owned - 
deswegen der Bezug auf das COM-Artige Interface - manche der DLLs sind 
noch nicht mal in C/C++ geschrieben

> Wenn man einen std::unique_ptr oder std::shared_ptr mit einem Deleter
> verwendet, welcher im selben Modul wie die Allokation definiert ist,
> wird es auch immer richtig aufgerufen - selbst wenn man den Smart
> Pointer an ein anderes Modul übergibt.

Extern habe ich so was ja auch - so eine Art CComPtr wie bei Microsoft - 
für intern möchte ich aber dennoch verhindern das man delete oder 
Stack-Allokation direkt benutzt weil das sonst zu schwer auffindbaren 
Fehler führt

von CppBert3 (Gast)


Lesenswert?

CppBert3 schrieb:
> Extern habe ich so was ja auch - so eine Art CComPtr wie bei Microsoft -
> für intern möchte ich aber dennoch verhindern das man delete oder
> Stack-Allokation direkt benutzt weil das sonst zu schwer auffindbaren
> Fehler führt

mein CComPtr ist eine std::unique_ptr Spezialisierung mit dem 
Module.Deleter

von Rasputin (Gast)


Lesenswert?

Rasputin schrieb:
> Ich glaube, ich verstehe, was du möchtest. Das Passkey-Idiom
> könnte
> deine Lösung sein:
> https://arne-mertz.de/2016/10/passkey-idiom/

Hier ein Beispiel, wie du dein Problem damit lösen könntest:

https://onlinegdb.com/H1I_Qt15E

von CppBert3 (Gast)


Lesenswert?

Auch eine schöne Idee - Danke

von Dirk K. (merciless)


Lesenswert?

Irgendwie habe ich keine Grund gelesen, warum du
die direkte Erzeugung verhindern willst. Ich
persönlich halte davon gar nichts, ich würde mich
gegängelt fühlen.

Wenn es darum geht, Fehler zu vermeiden, wären gute
Beispiele und eine saubere Dokumentation vernünftiger.

merciless

von Mark B. (markbrandis)


Lesenswert?

Dirk K. schrieb:
> Irgendwie habe ich keine Grund gelesen, warum du
> die direkte Erzeugung verhindern willst. Ich
> persönlich halte davon gar nichts, ich würde mich
> gegängelt fühlen.
>
> Wenn es darum geht, Fehler zu vermeiden, wären gute
> Beispiele und eine saubere Dokumentation vernünftiger.

Dies.

Manchmal versucht man Probleme an einer Stelle zu lösen, wo diese gar 
nicht existieren. So vermutlich auch hier.

von CppBert3 (Gast)


Lesenswert?

Dirk K. schrieb:
> Irgendwie habe ich keine Grund gelesen, warum du
> die direkte Erzeugung verhindern willst. Ich
> persönlich halte davon gar nichts, ich würde mich
> gegängelt fühlen.
>
> Wenn es darum geht, Fehler zu vermeiden, wären gute
> Beispiele und eine saubere Dokumentation vernünftiger.
>
> merciless

weil direktes new/delete oder auch auf dem Stack anlegen in meinem Fall 
definitiv falsch ist - COM-Konzept/Unterschiedliche Heaps/mehrere DLLs - 
nicht alles in C/C++

von CppBert3 (Gast)


Lesenswert?

Mark B. schrieb:
> Dirk K. schrieb:
>> Irgendwie habe ich keine Grund gelesen, warum du
>> die direkte Erzeugung verhindern willst. Ich
>> persönlich halte davon gar nichts, ich würde mich
>> gegängelt fühlen.
>>
>> Wenn es darum geht, Fehler zu vermeiden, wären gute
>> Beispiele und eine saubere Dokumentation vernünftiger.
>
> Dies.
>
> Manchmal versucht man Probleme an einer Stelle zu lösen, wo diese gar
> nicht existieren. So vermutlich auch hier.

Hier ist das Problem eher das ich ein Konzept habe welches ich nicht 
ändern kann aber trotzdem sicherer in der Benutzung machen will

Aber es sind ein paar Tips zusammen gekommen die mich weiter bringen
btw: new/delete verhinder ich jetzt per CRTP - weil ich das sowie so 
schon für meine veröffentlichen Klassen benutzte um 
Implementationsschnickschnack zu veringern

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.