|
|
От: | Аноним | |
| Дата: | 05.09.06 20:09 | ||
| Оценка: | 117 (13) +1 -3 | ||
class File
{
// неявное копирование запрещено
File(const File& s);
File& operator=(const File& s);
public:
struct Params
{
string Path;
int ShareMode;
};
explicit File(const Params& p);
private:
...
};
class FileList
{
// неявное копирование запрещено
FileList(const FileList& s);
FileList& operator=(const FileList& s);
public:
void AddFile(const string& Path, int ShareMode);
private:
list<File> m_Files;
};
void FileList::AddFile(const string& Path, int ShareMode)
{
File::Params p;
p.Path = Path;
p.ShareMode = ShareMode;
m_Files.push_back(p);
}void PrintItems(const list<string>& Items)
{
for (list<string>::const_iterator it = Items.begin(); it != Items.end(); ++it)
{
cout << *it << '\n';
}
}Никто из высказавшихся на форуме не заметил отсутствия '&'. gunf сказал, что у него "около 100 000 точек".class POINT3D { private: double getxyz(int i); void setxyz(int i,double v); protected: public: double x,y,z; POINT3D():x(0),y(0),z(0){}; __property double xyz[int] = { read = getxyz , write = setxyz }; }; typedef std ::vector<POINT3D,std::allocator<POINT3D> >LINE; typedef std ::vector<LINE,std::allocator<LINE> >SURF; ... void __fastcall TMyPanel::Mesh (SURF matr) { for (int i = 0; i<int(matr.size()); i++) { for (int j = 1; j<int(matr[i].size()); j++) { glBegin(GL_LINES); glVertex3d(matr[i][j-1].x,matr[i][j-1].y,matr[i][j-1].z); glVertex3d(matr[i][j].x,matr[i][j].y,matr[i][j].z); glEnd(); } } }
Соответственно, оно запрещено и для всех наследников CObject, включая CArray, CList и CMap. CString неявно копируется (в MFC 4.2 дёшево).class CObject { ... // Disable the copy constructor and assignment by default so you will get // compiler errors instead of unexpected behaviour if you pass objects // by value or assign objects. protected: CObject(); private: CObject(const CObject& objectSrc); // no implementation void operator=(const CObject& objectSrc); // no implementation ... };
if (m_itSelectedItem != m_pServer->ItemsEnd())
{
m_pServer->ReleaseItem(m_itSelectedItem);
m_itSelectedItem = m_pServer->ItemsEnd();
}if (m_itSelectedItem != NULL) // NULL-итератор
{
m_pServer->ReleaseItem(m_itSelectedItem);
m_itSelectedItem = NULL; // NULL-итератор
}template<typename TElem, ...>
class vector
{
...
typedef TElem* iterator;
...
};
template<typename TElem, ...>
class list
{
...
struct Node
{
Node* pPrev;
Node* pNext;
TElem Elem;
};
...
class iterator
{
Node* m_pNode;
...
};
...
};Поэтому POSITION вполне законно может быть NULL. Хотя такой вариант итераторов не type-safe, так как для всех конкретизаций CList и CMap используется один и тот же тип.// abstract iteration position struct __POSITION { }; typedef __POSITION* POSITION;
pCmdUI->Enable(pFrame->m_UndoRedo.GetPos() < pFrame->mUndoRedo.buffer.GetSize() - 1);pCmdUI->Enable(pFrame->m_UndoRedo.GetPos() < (int) pFrame->mUndoRedo.buffer.size() - 1);Если size_type = size_t (по умолчанию), то условие "0 <= i" бессмысленно, так как значение переменной беззнакового типа всегда >= 0. Как ни странно, код работает правильно, так как no_of_erased — это количество элементов vector-а v, у которых erased = true.template<...> void hash_map::resize(size_type s) { ... if (no_of_erased) { for (size_type i = v.size() - 1; 0 <= i; i--) if (v[i].erased) { v.erase(&v[i]); if (--no_of_erased == 0) break; } } ... }
Именно эти правила неявного преобразования типов "подменили" -1 на 4294967295 в программе Кирпы.Типы unsigned (без знака) идеально подходят для задач, в которых память интерпретируется как массив битов. Использование unsigned вместо int с целью заработать лишний бит для представления положительных целых почти всегда оказывается неудачным решением. Использование же объявления unsigned для гарантии того, что целое будет неотрицательным, почти никогда не сработает из-за правил неявного преобразования типов (§ В.6.1, § В.6.2.1).
Какое отношение size_t имеет к array-based контейнерам (vector, string), ещё понятно: в языках C/C++ длина/индекс массива выражаются типом size_t. Какое отношение size_t имеет к node-based контейнерам (list, map), непонятно совсем. В 90-ые годы (время проектирования STL), когда ещё живы были 16-битные платформы, использование size_t было оправдано. Сейчас это источник тонких ошибок.[18] Избегайте беззнаковой арифметики; § 4.4.
[19] С подозрением относитесь к преобразованиям из signed в unsigned и из unsigned в signed; § В.6.2.6.
template<typename TElem>
class MyList : public list<TElem>
{
public:
int size() const { return list<TElem>::size(); }
};Реализации operator[] проверяют (ASSERT-ами), что индекс >= 0. В преддверии Win64 int обобщили до INT_PTR.template<...> class CArray : public CObject { ... int GetSize() const; ... // overloaded operator helpers TYPE operator[](int nIndex) const; TYPE& operator[](int nIndex); ... }; template<...> class CList : public CObject { ... // count of elements int GetCount() const; ... }; template<...> class CMap : public CObject { ... // number of elements int GetCount() const; ... }; class CString { ... // get data length int GetLength() const; ... // return single character at zero-based index TCHAR operator[](int nIndex) const; ... };
class Item
{
public:
void AddRef();
void Release();
string Name() const;
private:
friend class ItemManager;
ItemManager* m_pManager;
int m_Refs;
string m_Name;
Item(ItemManager* pManager, const string& Name);
};
class ItemManager
{
public:
Item* AddItem(const string& Name);
private:
friend class Item;
list<Item> m_Items;
void RemoveItem(Item* pItem);
};
Item* ItemManager::AddItem(const string& Name)
{
m_Items.push_back(Item(this, Name));
return &m_Items.back();
}
void ItemManager::RemoveItem(Item* pItem)
{
// получить итератор по указателю на элемент списка
list<Item>::iterator it = m_Items.begin();
while (&*it != pItem)
{
++it;
}
m_Items.erase(it);
}
Item::Item(ItemManager* pManager, const string& Name) :
m_pManager(pManager),
m_Refs(1),
m_Name(Name)
{
}
void Item::AddRef()
{
m_Refs++;
}
void Item::Release()
{
m_Refs--;
if (m_Refs == 0)
{
m_pManager->RemoveItem(this);
}
}template<typename TElem, ...>
class vector
{
...
typedef TElem* iterator;
...
static iterator iterator_from_pointer(TElem* pElem)
{
return pElem;
}
...
};
template<typename TElem, ...>
class list
{
...
struct Node
{
Node* pPrev;
Node* pNext;
TElem Elem;
};
...
class iterator
{
Node* m_pNode;
...
};
...
static iterator iterator_from_pointer(TElem* pElem)
{
iterator it;
it.m_pNode = reinterpret_cast<Node*>(reinterpret_cast<Byte*>(pElem) - offsetof(Node, Elem));
assert(&it.m_pNode->Elem == pElem);
return it;
}
...
};template<typename TElem>
class MyList : public list<TElem>
{
public:
bool has_elems() const { return !empty(); }
};Там же есть сноска:Одобрен также класс динамического массива dynarray [Stal, 1993], шаблон класса bits<N> для битовых множеств фиксированного размера, класс bitstring для битовых множеств с изменяемым размером. Кроме того, комитет принял классы комплексных чисел (предшественник — первоначальный класс complex, см. раздел 3.3), обсуждается вопрос, следует ли принять класс вектора для поддержки численных расчётов и научных приложений. О наборе стандартных классов, их спецификациях и даже названиях всё ещё ведутся оживлённые споры.
Видимо, в ходе стандартизации, кто-то, слабо знакомый с математикой, переименовал dynarray в vector и спрятал bitstring под маской vector<bool>. Может быть, повлияла традиция. Функцию main обычно пишут так:...
Разумеется, STL содержит классы для отображений и списков и включает в качестве частных случаев вышеупомянутые классы dynarray, bits и bitstring. Кроме того, комитет одобрил классы векторов для поддержки численных и научных расчётов, приняв за основу предложение Кена Баджа из Sandia Labs.
int main(int argc, char* argv[])
{
...
}О проблеме писали здесьtemplate<class TYPE, class ARG_TYPE> AFX_INLINE int CList<TYPE, ARG_TYPE>::GetCount() const { return m_nCount; }
template<typename TElem>
class MyList : public list<TElem>
{
public:
typename iterator push_front(const TElem& e)
{
list<TElem>::push_front(e);
return begin();
}
typename iterator push_back(const TElem& e)
{
list<TElem>::push_back(e);
typename iterator it = end();
return --it;
}
};// add before head or after tail POSITION AddHead(ARG_TYPE newElement); POSITION AddTail(ARG_TYPE newElement);
class ImmutString : public string
{
public:
ImmutString(const char s[]) :
string(s)
{
}
ImmutString(const char s[], int L) :
string(s, L)
{
}
const_iterator begin() const
{
return string::begin();
}
const_iterator end() const
{
return string::end();
}
const_reverse_iterator rbegin() const
{
return string::rbegin();
}
const_reverse_iterator rend() const
{
return string::rend();
}
char operator[](int Index) const
{
return string::operator[](Index);
}
char at(int Index) const
{
return string::at(Index);
}
};Если вы действительно хотите изменить содержимое CString-а, вы должны сказать это явно (метод SetAt). В MFC 4.2 CString считает ссылки, поэтому метод SetAt делает copy-on-write, но разделяемость буфера не запрещает.class CString { ... // return single character at zero-based index TCHAR operator[](int nIndex) const; // set a single character at zero-based index void SetAt(int nIndex, TCHAR ch); ... };
string Text = "abc";
assert(Text[3] == '\0');bool IsValidMethodName_CStyle(const char pText[])
{
int p = 0;
// Имя1 не может начинаться с цифры
if (IsLetterOrUnderscore(pText[p])) p++; else return false;
while (IsLetterOrUnderscoreOrDigit(pText[p])) p++;
if (pText[p] == ':') p++; else return false;
if (pText[p] == ':') p++; else return false;
// Имя2 не может начинаться с цифры
if (IsLetterOrUnderscore(pText[p])) p++; else return false;
while (IsLetterOrUnderscoreOrDigit(pText[p])) p++;
return pText[p] == '\0';
}bool IsValidMethodName_STL(const string& Text)
{
int p = 0;
// Имя1 не может начинаться с цифры
if ((p < Text.length()) && IsLetterOrUnderscore(Text[p])) p++; else return false;
while ((p < Text.length()) && IsLetterOrUnderscoreOrDigit(Text[p])) p++;
if ((p < Text.length()) && (Text[p] == ':')) p++; else return false;
if ((p < Text.length()) && (Text[p] == ':')) p++; else return false;
// Имя2 не может начинаться с цифры
if ((p < Text.length()) && IsLetterOrUnderscore(Text[p])) p++; else return false;
while ((p < Text.length()) && IsLetterOrUnderscoreOrDigit(Text[p])) p++;
return p == Text.length();
}_AFX_INLINE TCHAR CString::operator[](int nIndex) const { // same as GetAt ASSERT(nIndex >= 0); ASSERT(nIndex < GetData()->nDataLength); return m_pchData[nIndex]; }
string Text;
int Len = ::GetWindowTextLength(hEditControl);
if (Len != 0)
{
Text.resize(Len);
::GetWindowText(hEditControl, &Text[0], Len + 1);
}string Text;
int Len = ::GetWindowTextLength(hEditControl);
if (Len != 0)
{
Text.resize(Len);
::GetWindowText(hEditControl, const_cast<char*>(Text.c_str()), Len + 1);
}string Text;
int Len = ::GetWindowTextLength(hEditControl);
if (Len != 0)
{
vector<char> Buf(Len + 1); // нужно место для завершающего '\0'
::GetWindowText(hEditControl, &Buf[0], Len + 1);
Text.assign(&Buf[0], Len);
}//#define GENERIC_STL_IMPL
//#define REALISTIC_STL_IMPL
class StringBuf
{
// неявное копирование запрещено
StringBuf(const StringBuf& s);
StringBuf& operator=(const StringBuf& s);
public:
StringBuf(string* pTarget, int Len);
char* Chars();
void Commit();
private:
#ifdef GENERIC_STL_IMPL
string* m_pTarget;
vector<char> m_Buf;
#endif
#ifdef REALISTIC_STL_IMPL
string* m_pTarget;
#endif
};
#ifdef GENERIC_STL_IMPL
StringBuf::StringBuf(string* pTarget, int Len)
{
assert(pTarget != NULL);
assert(pTarget->empty()); // строим string с нуля
assert(Len > 0);
m_pTarget = pTarget;
m_Buf.resize(Len + 1); // может понадобиться место для завершающего '\0'
}
char* StringBuf::Chars()
{
assert(m_pTarget != NULL); // ещё не было Commit
return &m_Buf[0];
}
void StringBuf::Commit()
{
assert(m_pTarget != NULL); // ещё не было Commit
m_pTarget->assign(&m_Buf[0], m_Buf.size() - 1); // без завершающего '\0'
m_pTarget = NULL;
m_Buf.clear(); // досрочно освободить память
}
#endif // GENERIC_STL_IMPL
#ifdef REALISTIC_STL_IMPL
StringBuf::StringBuf(string* pTarget, int Len)
{
assert(pTarget != NULL);
assert(pTarget->empty()); // строим string с нуля
assert(Len > 0);
m_pTarget = pTarget;
m_pTarget->resize(Len);
}
char* StringBuf::Chars()
{
assert(m_pTarget != NULL); // ещё не было Commit
return const_cast<char*>(m_pTarget->c_str());
}
void StringBuf::Commit()
{
assert(m_pTarget != NULL); // ещё не было Commit
m_pTarget = NULL;
}
#endif // REALISTIC_STL_IMPLstring Text;
int Len = ::GetWindowTextLength(hEditControl);
if (Len != 0)
{
StringBuf Buf(&Text, Len);
::GetWindowText(hEditControl, Buf.Chars(), Len + 1);
Buf.Commit();
}CString Text;
int Len = ::GetWindowTextLength(hEditControl);
if (Len != 0)
{
char* pBuf = Text.GetBufferSetLength(Len);
::GetWindowText(hEditControl, pBuf, Len + 1);
Text.ReleaseBuffer();
}struct ConcatString
{
const char* pChars;
int Len;
ConcatString(const string& s)
{
pChars = s.c_str();
Len = s.length();
}
// для строковых литералов
ConcatString(const char s[])
{
pChars = s;
Len = strlen(s);
}
};
string DoConcat(const ConcatString pStrings[], int NumStrings)
{
assert(NumStrings > 0);
int TotalLen = 0;
for (int i = 0; i < NumStrings; i++)
{
assert(pStrings[i].Len >= 0);
TotalLen += pStrings[i].Len;
}
string Total;
if (TotalLen != 0)
{
StringBuf Buf(&Total, TotalLen);
char* pTotIter = Buf.Chars();
for (int i = 0; i < NumStrings; i++)
{
ConcatString s = pStrings[i];
if (s.Len != 0)
{
memcpy(pTotIter, s.pChars, s.Len * sizeof(char));
pTotIter += s.Len;
}
}
Buf.Commit();
}
return Total;
}
string Concat(ConcatString s1, ConcatString s2)
{
const ConcatString Strings[] = { s1, s2 };
return DoConcat(Strings, 2);
}
string Concat(ConcatString s1, ConcatString s2, ConcatString s3)
{
const ConcatString Strings[] = { s1, s2, s3 };
return DoConcat(Strings, 3);
}
// и так далееstring DirPath = "C:\\Projects";
string FileName = "Notes.txt";
string FilePath = Concat(DirPath, "\\", FileName);