From: Barry on
Hi there,

I wish to have an Images singleton object in my program which stores
all my image objects. I then wish to access a particular image via a
unique identifier. To do this, I have created an enum which is equal
in length with the number of images stored in the singleton. I then
use a std::map to store the images with the enum used as the key.

Currently an image contains two strings: a name (used by the image
player) and a file name. An Image object is passed to an ImagePlayer
object elsewhere in my code.

The code I have come up with allows me to check that I am using all
the enum values and that I don't use the same name for an Image more
than once. However, the enum is of course hard coded. Therefore I
can't reuse this code in my other projects which use a different set
of Images, without rewriting the enum.

Have you any ideas how I should solve this problem? Should I give up
on using the enum?

Thanks very much for your help,

Magnus

// Images.h
#pragma once

#include <map>
#include "Image.h"

#define IMAGE_IDS {MOVIE_1, MOVIE_2, MOVIE_3, OLD_MOVIE_1,
OLD_MOVIE_2, SHORT_CLIP}

enum ImageId IMAGE_IDS;

class Images : public std::map<const ImageId, const Image>
{
public:
static Images& Instance();
void LoadIntoImagePlayer() const;

private:
const bool AreAllImageIdsInUse() const;
const bool AreAllImageNamesUnique() const;
};

// Images.cpp
#include "StdAfx.h"
#include <assert.h>
#include <vector>
#include <set>
#include "Images.h"

Images& Images::Instance()
{
static Images images;
return images;
}

const bool Images::AreAllImageIdsInUse() const
{
// make sure that we're using all our enums
const ImageId imageIds[] = IMAGE_IDS;
return this->size()==sizeof(imageIds)/sizeof(ImageId);
}

const bool Images::AreAllImageNamesUnique() const
{
// ensure that all the images have a unique name
std::vector<const Image> images;
std::map<const ImageId, const Image>::const_iterator i=this->begin();
for(;i!=this->end();++i)
images.push_back(i->second);
std::set<const Image> uniqueImageNames(images.begin(),images.end());
return this->size()==uniqueImageNames.size();
}

void Images::LoadIntoImagePlayer() const
{
assert(AreAllImageIdsInUse());
assert(AreAllImageNamesUnique());

//...
}

// Image.h
#pragma once

#include <string>

class Image
{
public:
Image();
Image(const std::string& name, const std::string& fileName);
Image& operator=(const Image&);
const bool operator==(const Image&) const;
const bool operator<(const Image&) const;
const std::string Name() const;
const std::string FileName() const;

private:
std::string m_name;
std::string m_fileName;
};

// Image.cpp
#include "StdAfx.h"
#include "Image.h"

Image::Image()
:m_name(""), m_fileName("")
{
}

Image::Image(const std::string& name, const std::string& fileName)
:m_name(name), m_fileName(fileName)
{
}

Image& Image::operator=(const Image& image)
{
if (this != &image)
{
m_name = image.m_name;
m_fileName = image.m_fileName;
}
return *this;
}

const bool Image::operator==(const Image& image) const
{
return m_name==image.m_name;
}

const bool Image::operator<(const Image& image) const
{
return m_name<image.m_name;
}

const std::string Image::Name() const
{
return m_name;
}

const std::string Image::FileName() const
{
return m_fileName;
}


--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

From: Alf P. Steinbach on
* Barry:
> Hi there,
>
> I wish to have an Images singleton object in my program which stores
> all my image objects. I then wish to access a particular image via a
> unique identifier. To do this, I have created an enum which is equal
> in length with the number of images stored in the singleton. I then
> use a std::map to store the images with the enum used as the key.
>
> Currently an image contains two strings: a name (used by the image
> player) and a file name. An Image object is passed to an ImagePlayer
> object elsewhere in my code.
>
> The code I have come up with allows me to check that I am using all
> the enum values and that I don't use the same name for an Image more
> than once. However, the enum is of course hard coded. Therefore I
> can't reuse this code in my other projects which use a different set
> of Images, without rewriting the enum.
>
> Have you any ideas how I should solve this problem? Should I give up
> on using the enum?
>
> Thanks very much for your help,
>
> Magnus
>
> // Images.h
> #pragma once
>
> #include <map>
> #include "Image.h"
>
> #define IMAGE_IDS {MOVIE_1, MOVIE_2, MOVIE_3, OLD_MOVIE_1,
> OLD_MOVIE_2, SHORT_CLIP}
>
> enum ImageId IMAGE_IDS;
>
> class Images : public std::map<const ImageId, const Image>
> {
> public:
> static Images& Instance();
> void LoadIntoImagePlayer() const;
>
> private:
> const bool AreAllImageIdsInUse() const;
> const bool AreAllImageNamesUnique() const;
> };
>
> // Images.cpp
> #include "StdAfx.h"
> #include <assert.h>
> #include <vector>
> #include <set>
> #include "Images.h"
>
> Images& Images::Instance()
> {
> static Images images;
> return images;
> }
>
> const bool Images::AreAllImageIdsInUse() const
> {
> // make sure that we're using all our enums
> const ImageId imageIds[] = IMAGE_IDS;
> return this->size()==sizeof(imageIds)/sizeof(ImageId);
> }
>
> const bool Images::AreAllImageNamesUnique() const
> {
> // ensure that all the images have a unique name
> std::vector<const Image> images;
> std::map<const ImageId, const Image>::const_iterator i=this->begin();
> for(;i!=this->end();++i)
> images.push_back(i->second);
> std::set<const Image> uniqueImageNames(images.begin(),images.end());
> return this->size()==uniqueImageNames.size();
> }
>
> void Images::LoadIntoImagePlayer() const
> {
> assert(AreAllImageIdsInUse());
> assert(AreAllImageNamesUnique());
>
> //...
> }
>
> // Image.h
> #pragma once
>
> #include <string>
>
> class Image
> {
> public:
> Image();
> Image(const std::string& name, const std::string& fileName);
> Image& operator=(const Image&);
> const bool operator==(const Image&) const;
> const bool operator<(const Image&) const;
> const std::string Name() const;
> const std::string FileName() const;
>
> private:
> std::string m_name;
> std::string m_fileName;
> };
>

[snip]

Much crucial information missing here, but I'm guessing that the main problem is a procedural approach that is sort of force-fit into C++ classes.

Applying my well known Telepathic Inference Powers (TIP) I surmise that

(1) the purpose of the enum is to identify images with some checking at
compile time, for some usage not even hinted at in the article,

(2) the purpose of the image names-as-strings is to support some code,
perhaps the "player"?, that requires string identifiers, and that

(3) the std::map iterator identification scheme is for iterating through
the images in order to load them into the "player", and perhaps in
order to present them in a menu or something.

Is this correct?

And where do the file names come from?

Are they hard-coded somewhere?

It seems that much of the problem with establishing a class invariant at object construction time is tied in with associating images with file names, combined with a desire to use a singleton. Is this correct? And why the singleton?


Cheers,

- Alf

--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]