Extra null when a struct is printed with writeln - d

In the code below what is that extra null in the output when an instance of S2 is printed with writeln ?
$ dmd -de -w so_004.d && ./so_004
S1("A", 1)
S2("A", 1, null)
If I define S2 in a package scope (i.e. outside main function) the null disappears.
Compiled with a reasonable recent DMD:
$ dmd --version
DMD64 D Compiler v2.083.0
Copyright (C) 1999-2018 by The D Language Foundation, All Rights Reserved written by Walter Bright
I noticed the issue when I was learning opEquals and I'm not planning to define types in sub-scopes in "real" code.
import std.stdio;
void main() {
{
struct S1 { string id; ushort x; }
auto a = S1("A", 1);
assert(a == a);
writeln(a);
}
{
struct S2 {
string id; ushort x;
bool opEquals()(auto ref const string rhs) const {
return id == rhs;
}
}
auto a = S2("A", 1);
assert(a == "A");
writeln(a);
}
}

It's the context pointer (called this in S2.tupleof), referring to the stack frame on which the S2 instance is created. This would generally be used in code like this:
auto fun(int n) {
struct S {
int get() { return n; }
}
return S();
}
The above code would allocate n on the heap, and place a pointer to it in S's this member.
Now, as for why it's in your code - that's a bug. There's no need for the context pointer, as the struct is not using any variables from its scope. To remove it, simply mark S2 as static:
static struct S2 {
string id; ushort x;
bool opEquals()(auto ref const string rhs) const {
return id == rhs;
}
}
auto a = S2("A", 1);
writeln(a); // S2("A", 1)

Related

Best Way To Destruct Global And Static Objects?

What is the best way to end the lifetime of an object with static storage duration?
Current implementation finds the caller of __run_exit_handlers which then will be used to determine the __exit_funcs.
However this would easily fail since offset to __run_exit_handlers can change easily even in glibc with the same version. Another thing that could be done is to resolve the address of __run_exit_handlers first then use it in finding the caller rather than using a hardcoded call offset.
Current Working Code:
#include <iostream>
#include <fstream>
#include <cstddef>
#include <cstdint>
#include <cstring>
#include <cstdio>
#include <execinfo.h>
struct A
{
A(std::string pName)
: mName(pName)
{
std::printf("%s %s\n", __PRETTY_FUNCTION__, mName.c_str());
}
~A()
{
std::printf("%s %s\n", __PRETTY_FUNCTION__, mName.c_str());
}
volatile int i = 0;
std::string mName;
};
A a{"a"};
A b{"b"};
A c{"c"};
class StaticDestroyer
{
public:
StaticDestroyer()
{
std::ifstream maps("/proc/self/maps", std::ios::in);
char line[1024];
uint8_t* magic = nullptr;
while (maps.getline(line, sizeof(line)))
{
char perms[4];
uint8_t *magicbegin, *magicend;
std::string lsv(line);
if (std::string::npos == lsv.find("/libc-",0,6)) continue;
std::sscanf(line, "%lx-%lx %4s", &magicbegin, &magicend, perms);
if (perms[0]==114 && perms[2]==120)
{
magic = findMagic(magicbegin, magicend);
break;
}
}
if (magic==nullptr)
throw std::runtime_error("magic not found!");
mHead = *(HakaishinNode**)magic;
}
bool destroy(void* pTarget)
{
HakaishinNode *current = mHead;
while (nullptr != current)
{
for (size_t i = current->idx-1 ; i>0; i--)
{
const Hakaishin *const f = &current->fns[i];
if (4 == f->type && pTarget == f->arg)
{
void (*destruct) (void *arg, int status) = f->fn;
asm ("ror $2*8+1, %0\nxor %%fs:%c2, %0" : "=r" (destruct) : "0" (destruct), "i" (48));
destruct (f->arg, 1);
if (current->idx-1 != i) for (size_t j = i; j < current->idx ; j++) current->fns[j] = current->fns[j+1];
current->idx--;
return true;
}
}
current = current->next;
}
return false;
}
private:
struct Hakaishin
{
long int type;
void (*fn) (void *arg, int status);
void *arg;
void *dso_handle;
};
struct HakaishinNode
{
struct HakaishinNode *next;
size_t idx;
Hakaishin fns[32];
};
uint8_t* findMagic(uint8_t* magicbegin, uint8_t* magicend)
{
const void* const begin = magicbegin;
int32_t ptr;
while ((magicbegin+7) <= magicend)
{
if (magicbegin[0]==0x48 && (magicbegin[1]==0x8b || magicbegin[1]==0x8d))
{
std::memcpy(&ptr, magicbegin+3, sizeof(ptr));
uint8_t* magicp = magicbegin+ptr+7;
if (ptr==0x38a5c1) return magicp;
}
magicbegin++;
}
return nullptr;
}
HakaishinNode* mHead = nullptr;
};
A& getA()
{
static A a{"getA"};
return a;
}
A& getA2()
{
static A a{"getA2"};
return a;
}
int main()
{
std::printf("entering...\n");
StaticDestroyer d;
d.destroy(&a);
d.destroy(&b);
auto& ga = getA();
d.destroy(&ga);
getA2();
std::printf("returning...\n");
}
Output:
A::A(std::string) a
A::A(std::string) b
A::A(std::string) c
entering...
A::~A() a
A::~A() b
A::A(std::string) getA
A::~A() getA
A::A(std::string) getA2
returning...
A::~A() getA2
A::~A() c
Static objects will be destructed with the termination of the program.
If you like to manage the resources don't make it static or use a static pointer. Here you can allocate and de-allocate the corresponding resources. This approach comes very close to a singleton, which is considered to be an anti pattern.
Conclusion:
If you need to manage a resource don't make it static.
The need to mess around with the default behavior of life-time in such a way indicates that you have a design flaw in your application.
So you should either consider restructuring your program to not use globals. Or at least change the way how you handle the globals. So if you really need globals and release them earlier, then switch to unique_ptr:
#include <iostream>
#include <functional>
#include <memory>
struct A
{
A(std::string pName)
: mName(pName)
{
std::printf("%s %s\n", __PRETTY_FUNCTION__, mName.c_str());
}
~A()
{
std::printf("%s %s\n", __PRETTY_FUNCTION__, mName.c_str());
}
volatile int i = 0;
std::string mName;
};
auto a = std::make_unique<A>("a");
auto b = std::make_unique<A>("b");
auto c = std::make_unique<A>("c");
auto& getA()
{
static auto a = std::make_unique<A>("getA");
return a;
}
auto& getA2()
{
static auto a = std::make_unique<A>("getA2");
return a;
}
int main() {
std::printf("entering...\n");
a = nullptr;
b = nullptr;
c = nullptr;
getA();
getA2();
getA() = nullptr;
std::printf("returning...\n");
}
That way you can release the objects managed by the unique_ptr earlier, but they will be released on exit automatically if you don't set them to nullptr manually.

C++ compiler optimization for linear pointer comparisons

I'm having the following code example (fairly representative of actual code), and I'm trying to make the compiler not emit comparisons for the inline index checks in getVal (line 32).
#include <stdio.h>
#include <stdint.h>
using TValue = uint32_t;
struct CI {
TValue* func;
};
struct LS {
TValue* top;
CI* ci;
};
LS* makeState() {
auto s = new LS();
s->ci = new CI();
s->ci->func = new TValue[4];
s->top = &s->ci->func[3];
return s;
}
inline int assertTop(LS* s, int idx) {
const TValue* o = s->ci->func + idx;
return ((uintptr_t)o <= (uintptr_t)s->top) ? 1 : 0;
}
inline uint32_t getVal(LS* s, int idx) {
const TValue* o = s->ci->func + idx;
if (o >= s->top) {
return -1;
}
return *o;
}
void check(LS* s) {
if (assertTop(s, 3)) {
printf("%d %d %d", getVal(s, 0), getVal(s, 1), getVal(s, 2));
}
}
int main()
{
auto s = makeState();
check(s);
return 0;
}
Practically, since this code can't be reached if the comparison in assertTop fails, and no other code with side effects is executed in between, these additional checks (emitted in check's usage of getVal as can be seen on the godbolt output) should not be needed.
I understand that pointer comparison is a 'weird' scenario that compilers usually will take the 'safe' route for and not optimize, but is there any other way to have the compiler not emit these checks, without actually removing the check from getVal?

C++ Break out of a function at an early stage

I have two questions.
The first is about working with functions. I need to break out of a function at an early stage under a condition.
For example:
std::string concat(std::string& x, std::string& y, std::vector<std::string>& vec)
{
if (atoi(x.c_str()) < 0)
{
return;
}
else {
std::string concatStr = y + x;
top_back(vec);
top_back(vec);
return concatStr;
}
}
As you can see, the function must return a string, but if the string x(which i of course convert to int) is less than 0, then I theoretically should break out of the function.
The problem with writing just return; is that the compiler tells me that it needs to return a value.
The second question is how can I remove the last line from the console?
That's connected with the first question, as someone suggested that return "";
is a good workaround, but it writes a blank space into the console, which in my case with the program I'm writing is not good and causes problems.
If you can compile using C++17 you can use std::optional to allow you to optionally return something from the function. We would rewrite your function to
std::optional<std::string> concat(std::string& x, std::string& y, std::vector<std::string>& vec)
{
if (atoi(x.c_str()) < 0)
{
return {};
}
else
{
std::string concatStr = y + x;
top_back(vec);
top_back(vec);
return concatStr;
}
}
And then in the call site you can use it like
auto ret = concat(some, stuff, here)
if(ret) // only print if ret actually holds a string
std::cout << *ret;
Alternatively you could use a unique_ptr and return an empty pointer if there is no result. The function would change to
std::unique_ptr<std::string> concat(std::string& x, std::string& y, std::vector<std::string>& vec)
{
if (atoi(x.c_str()) < 0)
{
return {};
}
else
{
std::string concatStr = y + x;
top_back(vec);
top_back(vec);
return std::make_unique<std::string>(concatStr);
}
}
but the call site would remain the same.
Lastly if a blank string is never going to be a valid return from the function you could just return that and handle it in the call site like
std::string concat(std::string& x, std::string& y, std::vector<std::string>& vec)
{
if (atoi(x.c_str()) < 0)
{
return {};
}
else
{
std::string concatStr = y + x;
top_back(vec);
top_back(vec);
return concatStr;
}
}
int main()
{
//...
auto ret = concat(some, stuff, here)
if(ret != "") // only print if ret actually holds a string
std::cout << ret;
//...
}
Because you are not satisfied with C++17 solutions, it is possible to write your own std::optional implementation.
template<typename T>
class Optional
{
bool m_HasValue;
T m_Object;
public:
Optional() : m_HasValue(false){};
Optional(T&& Object) : m_HasValue(true), m_Object(std::forward<T>(Object)){};
operator T&(){return m_Object;}
operator bool(){return m_HasValue;}
T& operator*(){return m_Object;}
};
This is a very simplified version of std::optional, but it will fulfill your needs.
Its usage remains the same as in this post above.
using std::string;
Optional<string> DoSomething(string Input)
{
if(Input == "dontprocessme")
return {}
// ... otherwise process the string
string Output;
// blah blah
return Output;
}
// ...
auto RetString = DoSomething("processme");
if(RetString)
std::cout << *RetString;

Unable to decipher "error: expected unqualified-id before 'int'"

I've been looking around and haven't come up with any tangible solutions. It sounds like it is looking for a default constructor instead of the one in place but I have one below. Moving it up as the first listed constructor didn't change the error messages so I'm wrong about that. Here's the full error message (using jGRASP):
In file included from intset.h:47:0,
from IntSet.cpp:1:
IntSet.cpp:12:11: error: expected unqualified-id before 'int'
IntSet(int a, int b, int c, int d, int e) {
^
IntSet.cpp:12:11: error: expected ')' before 'int'
Here's the IntSet.cpp code:
#include "intset.h"
//#include <algorithm>
//#include <iostream>
int size;
const int MAXSIZE = 25000;
bool set[MAXSIZE];
const int SENTINEL = -1;
//Constructors
IntSet(int a, int b, int c, int d, int e) {
size = a;
if(b > size) {
size = b;
}
if(c > size) {
size = c;
}
if(d > size) {
size = d;
}
if(e > size) {
size = e;
}
set = new bool[size];
for(int i = 0; i <= size; i++) {
if(i == a || i == b || i == c || i == d || i == e) {
insert(i);
} else {
remove(i);
}
}
}
IntSet(int a, int b, int c, int d) {
IntSet(a, b, c, d, -1);
}
IntSet(int a, int b, int c) {
IntSet(a, b, c, -1, -1);
}
IntSet(int a, int b) {
IntSet(a, b, -1, -1, -1);
}
IntSet(int a) {
IntSet(a, -1, -1, -1, -1);
}
//Copy constructor
IntSet(const IntSet& x) {
size = x.size;
for (int i = 0; i <= x.size; i++ ) {
set[i] = x.set[i];
}
}
//Destructor
~IntSet()
{
//for(int i = this.length(); i >= 0; i--) {
// this[i]
//}
}
////////////////////////
bool insert(int a) {
if(a <= size && a >= 0) {
set[a] = true;
return true;
}
else if(a >= 0) {
//removed "new" from line below
IntSet temp = IntSet(a);
&this += temp;
set[a] = true;
return true;
}
return false;
}
bool remove (int a) {
if (isInSet(a)) {
set[a] = false;
return true;
}
return false;
}
bool isEmpty() {
bool retVal = true;
for (int i = 0; i <= size; i++) {
if (set[i] == true) {
retVal = false;
}
}
return retVal;
}
bool isInSet (int a) {
if (set[a]){
return true;
}
return false;
}
/////////////////////////////////////////////
IntSet operator + (IntSet a) {
IntSet c = IntSet(max(size, a.size));
for (int i = 0; i <= c.size; i++) {
if (set[i] || a.set[i]){
c.set[i] = true;
}
else {
c.set[i] = false;
}
}
return c;
}
IntSet operator * (IntSet a) {
IntSet c = IntSet(max(size, a.size));
for (int i = 0; i <= c.size; i++) {
if (set[i] && a.set[i]) {
c.set[i] = true;
}
else {
c.set[i] = false;
}
}
return c;
}
IntSet operator - (IntSet a) {
IntSet c = IntSet();
c.size = 0;
for (int i = 0; i <= size; i++) {
if (set[i] && !a.set[i]) {
c.set[i] = true;
}
else {
c.set[i] = false;
}
c.size++;
}
return c;
}
IntSet operator = (const IntSet a) {
return IntSet(a);
}
IntSet operator += (IntSet a) {
return IntSet(operator+(a));
}
IntSet operator *= (IntSet a) {
return IntSet(operator * (a));
}
IntSet operator -= (IntSet a) {
return IntSet(operator - (a));
}
IntSet operator == (const IntSet a) const{
for(int i = 0; i < size; i++) {
if(set[i] != a.set[i]) {
return false;
}
}
return true;
}
IntSet operator != (IntSet a) {
for(int i = 0; i < size; i++) {
if(set[i] != a.set[i]) {
return true;
}
}
return false;
}
IntSet operator << (IntSet a) {
cout << "{";
for(int i = 0; i < size; i++) {
if(set[i]) {
cout << " " << i;
}
}
cout << "}";
}
IntSet operator >> (IntSet a) {
int index;
while(cin >> index && index != SENTINEL) {
insert(index);
}
}
Here is the attached intset.h code:
#ifndef INTSET_H
#define INTSET_H
#include <iostream>
#include <algorithm>
using namespace std;
class IntSet {
public:
//Constructors
IntSet();
IntSet(int);
IntSet(int, int);
IntSet(int, int, int);
IntSet(int, int, int, int);
IntSet(int, int, int, int, int);
IntSet(const IntSet&); // M: Added the &; must be a pointer or reference
~IntSet();
//Overloaded Operators M: Added 'IntSet' in front of the word 'operator.'
// It was required syntax.
IntSet operator+(IntSet);
IntSet operator*(IntSet);
IntSet operator-(IntSet);
IntSet operator=(IntSet);
IntSet operator+=(IntSet);
IntSet operator*=(IntSet);
IntSet operator-=(IntSet);
IntSet operator==(IntSet);
IntSet operator!=(IntSet);
IntSet operator<<(IntSet);
IntSet operator>>(IntSet);
//Functions
bool insert(int);
bool remove(int);
bool isEmpty();
bool isInSet(int);
private:
const int MAXSIZE;
int size;
bool set[];
const int SENTINEL;
};
#include "IntSet.cpp"
#endif
I haven't had much experience with header files so it wouldn't surprise me if I formatted something incorrectly but I'm looking at plenty of other samples provided by the professor and there isn't anything unusual about mine. I thought maybe it had something to do with the order listed in the .h file and that I wasn't following the same exact order in the .cpp but nothing changed when I had everything listed in the same order.
There is a lot that is wrong with your code. We are going to have to jump around a bit between the header and the implementation. Ready?
In your header you do this:
class IntSet {
/* stuff */
private:
bool set[];
};
First of all, the name set is a bad choice: it is the name of a class in namespace stdw which you are importing by having using namespace std in your header file. This can be confusing at best.
More importantly, the syntax bool set[] isn't correct in this context. Even if your compiler allows it, it's an extension. Who knows what it does and how it will behave on other compilers? Avoid it.
If you want to declare an array, declare an array. If you want to declare a pointer, declare a pointer. Just remember: an array isn't a pointer.
Unfortunately you don't, becase later on in your code you do this:
set = new bool[size];
What is this supposed to do? set isn't a pointer, it's some kind of array, and you cannot assign a pointer to an array.
Now, we get to the second problem: you declare some member variables for your class, in your header file:
class IntSet {
/* some stuff here */
private:
const int MAXSIZE;
int size;
bool set[];
const int SENTINEL;
};
Then in your implementation you have the following code floating up at the top:
int size;
const int MAXSIZE = 25000;
bool set[MAXSIZE];
const int SENTINEL = -1;
I don't think that this does what you think it does. It seems that your intention is to initialize those variables, but that's not what happens. Remember, those variables only exist as members variables that belong to a particular instance of a class, and they are not "free-standing". So what's happening here?
Well, this declares all these variables again, so you have variables called MAXSIZE, size, set and SENTINEL that are valid anywhere in that translation unit (i.e. the .cpp file), independent of the member variables in the class.
This, of course, means that the member variables with those names aren't initialized (well, except set which you assign a pointer to, which we already know is wrong). This will cause your code to exhibit undefined behavior. After all, the value of an uninitialized variable can be anything at all.
If your intention had been to initialize the class members, then you should remove that code and initialize those variables in your constructor(s):
IntSet::IntSet(int a, int b, int c, int d, int e)
: size(a), MAXSIZE(25000), SENTINEL(-1)
{
/* whatever*/
}
Notice, by the way, how I used IntSet:: in front of the constructor name? This is called the scope resolution operator. Remember, there is no constructor called IntSet. The constructor belongs to a class, which is called IntSet, and outside of that class, it's proper name is IntSet::IntSet. A small example may help:
class Test
{
int Length;
public:
/* notice how inside the class, you only need Test
* when providing a body for the constructor. This
* makes sense. You know which class you inside of.
*/
Test()
: Length(0)
{
}
Test(int len);
};
/* Now we are outside the class. We need to help
* the compiler out and tell it what class the
* function belongs to.
*/
Test::Test(int len)
: Length(len)
{
}
A tangential point as to do with the names that you are using. What's a? Why do you use a to initialize something called size? You should choose meaningful variables names that help document the code so that when you have to read it back your head doesn't explode.
Another tangential point is that if variables like MAXSIZE and SENTINEL are going to be shared between all instances of the class, then, for future reference, you should probably consider making them static class members.
Lastly, you have this bit of code in your header file
#include "IntSet.cpp"
This is, almost certainly, not correct. You should never do this (there may be some who think that there are exceptions, but don't learn bad habits at this point. When you know enough to stumble on this legitimately, then you will know enough to determine whether it's the right thing to do or not).
What makes it worse is that your implementation file contains:
#include "IntSet.h"
Think about what you are doing here: when the compiler is processing the file IntSet.h you are telling to also process the file IntSet.cpp. The file IntSet.cpp tells the compiler to process the file IntSet.h. Which tells the compiler to process the file IntSet.cpp. And so on and so forth.
Generally speaking, implementation files (.cpp) will include header files. Header files will only include other header files.
There are a few other issues, but you should probably fix all these things, and then, if you are still having issues, post a new question and we can go from there.
Good luck!
You need to put the name of the class and :: before defining a member function.
IntSet::IntSet(int a, int b, int c, int d, int e) {
//^^^^^^^^
//here
Do the same with the other constructors, the operators and methods.

Changing my struct to cpp style struct gives me run time error

typedef struct
{
int day;
int month;
int year;
} Date;
typedef struct
{
int a;
int s;
} MetaData;
struct A
{
char arrA[10];
char arrB[10];
Date date;
A(char * arrA, char *arrB, const Date& date)
{
strcpy(this->arrA, arrA);
strcpy(this->arrB, arrB);
this->date = date;
}
A(const A& a)
{
strcpy(this->arrA, a.arrA);
strcpy(this->arrB, a.arrB);
this->date = a.date;
}
};
bool operator < (const A & lhs, const A & rhs)
{
if(strcmp(lhs.arrA, rhs.arrA) == 0)
{
if(strcmp(lhs.arrB, lhs.arrB) == 0)
return false;
else return strcmp(lhs.arrB, lhs.arrB);
}
else
return strcmp(lhs.arrA, rhs.arrB);
}
typedef map<A, MetaData> TickerMap;
int main()
{
TickerMap tickerMap;
char x[10], y[10];
Date date;
A a(x, y, date);
MetaData m;
//tickerMap.insert(make_pair(a, m));
cout<<"The element is sucessfully inserted"<<endl;
return 0;
}
Whenever i create a struct with some constructors.It gives me run time error when i insert the object in the map. Can somebody please tell me the exact problem. It will be very helful. When I have normal structs ( C style) there is no problem during insertion.
Error :Run-Time Check Failure #2 - Stack around the variable 'date' was corrupted. (visual Studio)
x and y are uninitialized arrays, containing random garbage. In particular, they generally aren't NUL-terminated. When A's constructor strcpys from them, a buffer overrun occurs.
Your program exhibits undefined behavior. To the extent it appears to work with some compilers, it does so purely by accident.