My object's constructor is being interpreted strangely? [duplicate] - c++

This question already has answers here:
Why this statement does not call the constructors - C++
(2 answers)
Closed 1 year ago.
I have an object declaration Bitmap image(FileRead(filename)) that is ... really confused?
When I hover over filename in Visual Studio, it gives me the tooltip FileRead filename as if I were declaring a new variable in the parameter list. When I hover over image it gives me Bitmap image(FileRead filename) as if it were a function declaration. These are my only clues as the compiler only gives me a compilation error if I attempt to use one of image's methods, confirming that image at least isn't being interpreted as an object.
If I change the argument so it's Bitmap image(FileRead("strLiteral")) or if I add a second optional argument so it's Bitmap image(FileRead(filename), 4), the problem goes away. Maybe one of the other constructors is confusing it but... I'm fairly sure that type of ambiguity is it's own class of compilation error, what I'm getting is totally different?
I'm genuinely mystified, what could be going on here?
int main(int argc, char * argv[]){
const char * filename = "image.png";
Bitmap image(FileRead(filename));
// using either of these instead works as intended for some reason
Bitmap image(FileRead(filename), 4u);
Bitmap image(FileRead("image.png"));
// image.get*() generates the following compilation error:
// "Error C2228 left of '.getY' must have class/struct/union"
// "Error C2228 left of '.getX' must have class/struct/union"
for (uint32 y = 0; y < image.getY(); ++y) {
for (uint32 x = 0; x < image.getX(); ++x) {
}
}
return 0;
}
Here's all of the constructor signatures to FileRead and Bitmap, in case something in here was causing trouble.
class Bitmap {
friend Mipmaps;
public:
Bitmap();
Bitmap(const Bitmap & other, bool flipY = false);
Bitmap(Bitmap && other, bool flipY = false);
Bitmap & operator=(const Bitmap & other);
Bitmap & operator=(Bitmap && other);
Bitmap(FileRead & file, uint16 byteDepth = 4u, uint16 heightForVolume = 0, bool flipY = false);
Bitmap(const uint8 * compressedImgData, uint32 imgDataLen, uint16 byteDepth, uint16 heightForVolume = 0, bool flipY = false);
Bitmap(uint16 byteDepth, glm::u16vec2 size);
Bitmap(uint16 byteDepth, glm::u16vec3 size);
static Bitmap asBorrowed(uint8 * data, glm::u16vec4 size, TextureDim::Type dimensionality = TextureDim::dim2D);
...
uint16 getX() const { return m_size.x; }
uint16 getY() const { return m_size.y; }
};
class FileRead{
public:
FileRead(const char * filename, bool textMode = false, uint32 bufferSize = 4096);
...
};

This is a less common case of Most Vexing Parse, which got its name from reaction similar to yours.
The idea is that by application of Murphy law, if something can be translated wrong, it will, so if a declaration of variable looks like function declaration, it is the latter.
FileRead is a type name, in consequence FileRead(filename) can be read as FileRead filename according to syntax of declarations in C and C++, so what you have there a prototype of function named image:
Bitmap image(FileRead filename);

Related

VS2017: cannot add strings/wstrings

I have trouble understanding why the following code does not do what it should, VS2017 does not show an error and the solution is created, but the string is never what it should be:
void COrion::AddJournalMessage(CTextData *msg, const string &name)
{
WISPFUN_DEBUG("c194_f101");
CTextData *jmsg = new CTextData(msg);
jmsg->Text = name + jmsg->Text;
}
jmsg->Text is std::string.
now at runtime let's say 'name' is "Player:" and 'jmsg->Text' is "Hello World", I would expect the text after the code to be "Player:Hello World", but it is not. It's only "Player:" and I don't understand why.
I found a workaround in a way:
jmsg->Text = name.c_str() + jmsg->Text;
with this change it is "Player:Hello World".
Problem is, I still don't understand why the first one does not work.
Can someone explain where the problem is?
Is it specific to VS or something?
to make it clear: this is from an open source project I want to use, not code I wrote myself, but the problem has been the source of many bugs, since it is used in this way alot.
edit
CTextData class:
class CTextData : public CRenderTextObject
{
public:
bool Unicode = false;
TEXT_TYPE Type = TT_CLIENT;
uchar Font = 0;
uint Timer = 0;
uint MoveTimer = 0;
string Text = "";
wstring UnicodeText = L"";
uchar Alpha = 0xFF;
CRenderWorldObject *Owner = NULL;
CTextData();
CTextData(CTextData *obj);
virtual ~CTextData();
virtual bool IsText() { return true; }
bool CanBeDrawedInJournalGump();
CGLTextTexture m_Texture;
void GenerateTexture(
int maxWidth,
ushort flags = 0,
TEXT_ALIGN_TYPE align = TS_LEFT,
uchar cell = 30,
int font = -1);
};

C++ from linux to windows: 'does not evaluate to a constant'

I am trying to port this function from Linux to windows:
template<class TDescriptor, class F>
bool TemplatedVocabulary<TDescriptor,F>::loadFromBinaryFile(const std::string &filename) {
fstream f;
f.open(filename.c_str(), ios_base::in|ios::binary);
unsigned int nb_nodes, size_node;
f.read((char*)&nb_nodes, sizeof(nb_nodes));
f.read((char*)&size_node, sizeof(size_node));
f.read((char*)&m_k, sizeof(m_k));
f.read((char*)&m_L, sizeof(m_L));
f.read((char*)&m_scoring, sizeof(m_scoring));
f.read((char*)&m_weighting, sizeof(m_weighting));
createScoringObject();
m_words.clear();
m_words.reserve(pow((double)m_k, (double)m_L + 1));
m_nodes.clear();
m_nodes.resize(nb_nodes+1);
m_nodes[0].id = 0;
char buf[size_node];// fails
int nid = 1;
while (!f.eof()) {
f.read(buf, size_node);
m_nodes[nid].id = nid;
// FIXME
const int* ptr=(int*)buf;
m_nodes[nid].parent = *ptr;
//m_nodes[nid].parent = *(const int*)buf;
m_nodes[m_nodes[nid].parent].children.push_back(nid);
m_nodes[nid].descriptor = cv::Mat(1, F::L, CV_8U);
memcpy(m_nodes[nid].descriptor.data, buf+4, F::L);
m_nodes[nid].weight = *(float*)(buf+4+F::L);
if (buf[8+F::L]) { // is leaf
int wid = m_words.size();
m_words.resize(wid+1);
m_nodes[nid].word_id = wid;
m_words[wid] = &m_nodes[nid];
}
else
m_nodes[nid].children.reserve(m_k);
nid+=1;
}
f.close();
return true;
}
This line:
char buf[size_node];
will not compile, giving the error:
expression did not evaluate to a constant.
I have tried using:
std::vector<char> buf(size_node)
and:
char buf[size_node] = new char[];
but I see the same error. It seems like this is related to a run time constant vs compile time constant, as stated in the answer here:
Tuple std::get() Not Working for Variable-Defined Constant
But I am not sure how to get around it in this case. Thank you.
It should be
char *buf = new char[size_node];
Remember to delete the memory after use.
Or, just use std::vector. It's much safer.
std::vector<char> buf(size_node);
Then you'd have to change how buf is used. For example:
f.read(buf, size_node);
should become
f.read(buf.data(), size_node); //Only C++11

Array copy in parallel_for_each context

I’m very newbie in AMP C++. Everything works fine if I use ‘memcpy’ inside the ‘parallel_for_each’ function, but I do know it is not the best practice. I tried to use ‘copy_to’, but it raises an exception. Below follows a simplified code, focusing the issue, that I am having troubles. Thanks in advance.
typedef std::vector<DWORD> CArrDwData;
class CdataMatrix
{
public:
CdataMatrix(int nChCount) : m_ChCount(nChCount)
{
}
void SetSize(UINT uSize)
{
// MUST be multiple of m_ChCount*DWORD
ASSERT(uSize%sizeof(DWORD) == 0);
m_PackedLength = uSize/sizeof(DWORD);
m_arrChannels.resize(m_ChCount*m_PackedLength);
}
UINT GetChannelPackedLen() const
{
return m_PackedLength;
}
const LPBYTE GetChannelBuffer(UINT uChannel) const
{
CArrDwData::const_pointer cPtr = m_arrChannels.data() + m_PackedLength*uChannel;
return (const LPBYTE)cPtr;
}
public:
CArrDwData m_arrChannels;
protected:
UINT m_ChCount;
UINT m_PackedLength;
};
void CtypDiskHeader::ParalelProcess()
{
const int nJobs = 6;
const int nChannelCount = 3;
UINT uAmount = 250000;
int vch;
CArrDwData arrCompData;
// Check buffers sizes
ASSERT((~uAmount & 0x00000003) == 3); // DWORD aligned
const UINT uInDWSize = uAmount/sizeof(DWORD); // in size give in DWORDs
CdataMatrix arrChData(nJobs);
arrCompData.resize(nJobs*uInDWSize);
vector<int> a(nJobs);
for(vch = 0; vch < nJobs; vch++)
a[vch] = vch;
arrChData.SetSize(uAmount+16); // note: 16 bytes or 4 DWORDs larger than uInDWSize
accelerator_view acc_view = accelerator().default_view;
Concurrency::extent<2> eIn(nJobs, uInDWSize);
Concurrency::extent<2> eOut(nJobs, arrChData.GetChannelPackedLen());
array_view<DWORD, 2> viewOut(eOut, arrChData.m_arrChannels);
array_view<DWORD, 2> viewIn(eIn, arrCompData);
concurrency::parallel_for_each(begin(a), end(a), [&](int vch)
{
vector<DWORD>::pointer ptr = (LPDWORD)viewIn(vch).data();
LPDWORD bufCompIn = (LPDWORD)ptr;
ptr = viewOut(vch).data();
LPDWORD bufExpandedIn = (LPDWORD)ptr;
if(ConditionNotOk())
{
// Copy raw data bufCompIn to bufExpandedIn
// Works fine, but not the best way, I suppose:
memcpy(bufExpandedIn, bufCompIn, uAmount);
// Raises exception:
//viewIn(vch).copy_to(viewOut(vch));
}
else
{
// Some data processing here
}
});
}
It was my fault. In the original code, the extent of viewOut(vch) is a little bit larger than viewIn(vch) extent. Using this way, it raises an exception 'runtime_exception'. When catching it, it supplies the following message xcp.what() = "Failed to copy because extents do not match".
I fixed the code replacing the original code by: viewIn(vch).copy_to(viewOut(vch).section(viewIn(vch).extent));
It copies only the source extent, that is what I need. But only compiles without restricted AMP.
The has nothing to do with the parallel_for_each it looks like it is a known bug with array_view::copy_to. See the following post:
Curiosity about concurrency::copy and array_view projection interactions
You can fix this using an explicit view_as() instead. I believe in your case your code should look something like this.
viewIn(vch).copy_to(viewOut(vch));
// Becomes...
viewIn[vch].view_as<1>(concurrency::extent<1>(uInDWSize)).copy_to(viewOut(vch));
I can't compile your example so was unable to verify this but I was able to get an exception from similar code and fix it using view_as().
If you want to copy data within a C++ AMP kernel then you need to do it as assignment operations on a series of threads. The following code copies the first 500 elements of source into the smaller dest array.
array<int, 1> source(1000);
array<int, 1> dest(500);
parallel_for_each(source.extent, [=, &source, &dest](index<1> idx)
{
if (dest.extent.contains(idx))
dest[idx] = source[idx];
});

static variables in switch statements

I am working on a keil project using c. In one of my files, I have defined some variables at the top as static. I use them in some functions in this file and I also use them in a switch/case statement. For example:
at the top where variables are defined:
static uint8_t* imageData = 0;
static uint32_t height = 0;
static uint32_t width = 0;
static uint32_t stride = 0;
in the middle of the code:
switch (pMsg->MsgId)
{
case WM_CREATE:
{
CAMERA_Init();
AMProcessor *processor = new AMProcessor();
struct block blocks[2] = {
{2, 240, 160},
{2, 160, 120}
};
processor->initBlocks(blocks, 2);
stride = 480; //sample_image.width;
processor->Initialize(480, 272, 480, InputTypes::CHROMA_MOBILE, InputTypes::RGB);
BSP_LED_Toggle(LED3);
while(1){
const PictureOutput* picOut = processor->ProcessImage((uint8_t *)CAMERA_FRAME_BUFFER);
break;
}
}
and near the bottom I have a couple of functions that also use these variables.
However, I am getting warnings that are telling me that the 4 variables defined at the top are initialized but never referenced. If they are not static then I do not get this warning, but I get a hard fault error (which I am trying to get rid of).
So my question is, why are these not referenced? It obviously has something to do with the static definition, but how come the static definition wouldn´t allow these to be referenced?
for clarification: I am getting this message on all of them, even stride.
warning: #177-D: variable "imageData" was declared but never referenced
I have a function at the bottom that uses all of these variables that looks like this:
bool ReadImageFromPgmFile(const char* pFileName, uint32_t &height, uint32_t &width, uint8_t*& ImgData) {
if (pFileName == 0) {
return false;
};
// read data from file
if (strstr(pFileName, ".pgm") || strstr(pFileName, ".PGM")) {
FILE *pPgmFile = fopen(pFileName, "r");
if (pPgmFile == NULL) {
fprintf(stderr, "Cannot open PGM file '%s'.\n", pFileName);
return false;
};
char x = fgetc(pPgmFile);
char y = fgetc(pPgmFile);
if (x != 'P' || y != '5') {
fprintf(stderr, "Invalid PGM file '%s'.\n", pFileName);
return false;
};
uint32_t maxvalue;
fscanf(pPgmFile, "%d", &width);
fscanf(pPgmFile, "%d", &height);
fscanf(pPgmFile, "%d", &maxvalue);
if (maxvalue > 255) {
fprintf(stderr, "File '%s' has incorrect format.\nOnly 8-bit PGMs are supported by this reader.\n", pFileName);
return false;
};
ImgData = new uint8_t[width*height];
memset(ImgData, 0, width*height);
fgetc(pPgmFile); // skip new line character
uint32_t nPixelsRead = fread(ImgData, 1, width * height, pPgmFile);
fclose(pPgmFile);
if (nPixelsRead != width * height) {
fprintf(stderr, "PGM file '%s' does not contain all pixels.\n", pFileName);
return false;
};
return true;
}
return false;
};
The method declaration hides the static height and width variables.
bool ReadImageFromPgmFile(const char* pFileName,
uint32_t &height,
uint32_t &width,
uint8_t*& ImgData) {
Use of height and width in this method will refer to the local parameters and not the static variables. I cannot see any reference to imageData, though there is an ImgData parameter that is used.
The static keyword in this context means the variables are only visible to the compilation unit it is declared in. Removing the static keyword makes it a global variable; accessible by the whole program. The compiler is unable (or unwilling) to reason about the usage of globals so you do not get the warnings.

Function has corrupt return value

I have a situation in Visual C++ 2008 that I have not seen before. I have a class with 4 STL objects (list and vector to be precise) and integers.
It has a method:
inline int id() { return m_id; }
The return value from this method is corrupt, and I have no idea why.
debugger screenshot http://img687.imageshack.us/img687/6728/returnvalue.png
I'd like to believe its a stack smash, but as far as I know, I have no buffer over-runs or allocation issues.
Some more observations
Here's something that puts me off. The debugger prints right values in the place mentioned // wrong ID.
m_header = new DnsHeader();
assert(_CrtCheckMemory());
if (m_header->init(bytes, size))
{
eprintf("0The header ID is %d\n", m_header->id()); // wrong ID!!!
inside m_header->init()
m_qdcount = ntohs(h->qdcount);
m_ancount = ntohs(h->ancount);
m_nscount = ntohs(h->nscount);
m_arcount = ntohs(h->arcount);
eprintf("The details are %d,%d,%d,%d\n", m_qdcount, m_ancount, m_nscount, m_arcount);
// copy the flags
// this doesn't work with a bitfield struct :(
// memcpy(&m_flags, bytes + 2, sizeof(m_flags));
//unpack_flags(bytes + 2); //TODO
m_init = true;
}
eprintf("Assigning an id of %d\n", m_id); // Correct ID.
return
m_header->id() is an inline function in the header file
inline int id() { return m_id; }
I don't really know how best to post the code snippets I have , but here's my best shot at it. Please do let me know if they are insufficient:
Class DnsHeader has an object m_header inside DnsPacket.
Main body:
DnsPacket *p ;
p = new DnsPacket(r);
assert (_CrtCheckMemory());
p->add_bytes(buf, r); // add bytes to a vector m_bytes inside DnsPacket
if (p->parse())
{
read_packet(sin, *p);
}
p->parse:
size_t size = m_bytes.size(); // m_bytes is a vector
unsigned char *bytes = new u_char[m_bytes.size()];
copy(m_bytes.begin(), m_bytes.end(), bytes);
m_header = new DnsHeader();
eprintf("m_header allocated at %x\n", m_header);
assert(_CrtCheckMemory());
if (m_header->init(bytes, size)) // just set the ID and a bunch of other ints here.
{
size_t pos = DnsHeader::SIZE; // const int
if (pos != size)
; // XXX perhaps generate a warning about extraneous data?
if (ok)
m_parsed = true;
}
else
{
m_parsed = false;
}
if (!ok) {
m_parsed = false;
}
return m_parsed;
}
read_packet:
DnsHeader& h = p.header();
eprintf("The header ID is %d\n", h.id()); // ID is wrong here
...
DnsHeader constructor:
m_id = -1;
m_qdcount = m_ancount = m_nscount = m_arcount = 0;
memset(&m_flags, 0, sizeof(m_flags)); // m_flags is a struct
m_flags.rd = 1;
p.header():
return *m_header;
m_header->init: (u_char* bytes, int size)
header_fmt *h = (header_fmt *)bytes;
m_id = ntohs(h->id);
eprintf("Assigning an id of %d/%d\n", ntohs(h->id), m_id); // ID is correct here
m_qdcount = ntohs(h->qdcount);
m_ancount = ntohs(h->ancount);
m_nscount = ntohs(h->nscount);
m_arcount = ntohs(h->arcount);
You seem to be using a pointer to an invalid class somehow. The return value shown is the value that VS usually uses to initialize memory with:
2^32 - 842150451 = 0xCDCDCDCD
You probably have not initialized the class that this function is a member of.
Without seeing more of the code in context.. it might be that the m_id is out of the scope you expect it to be in.
Reinstalled VC++. That fixed everything.
Thank you for your time and support everybody! :) Appreciate it!