目前,我正在尝试实现运算符重载的概念,使其成为我自己的字符串类/函数。
我认为我正确地处理了这个问题;该代码可以成功运行。
但是我不确定我的代码是否以最佳方式编写(我是否需要将更多的方法/参数设为const?我是否会使用过多的代码?)并且我是否进行了良好的内存管理?
感谢所有反馈:)
#include <iostream>
#include <vector>
#include <string.h>
#include <stdio.h>
using namespace std;
class DynString {
private:
char *c;
public:
~DynString() { delete[]c; }
DynString() : c(NULL) {}
//second constructor
DynString(const char* input) {
int x = strlen(input) + 1;
c = new char[x];
strcpy(c, input);
}
//(copyconstructor) TRIO //QUATRO
DynString(const DynString& dynstring) {
c = new char[strlen(dynstring.c) + 1];
strcpy(this->c, dynstring.c);
}
//UNO
friend ostream& operator<< (ostream& lhs, DynString& a) {
lhs << a.c;
return lhs;
}
//DUO
char& operator[] (int i) {
return c[i];
}
//TRIO
DynString& operator+ (DynString& y) {
char *newArray = new char[strlen(y.c) + strlen(this->c) + 1];
strcpy(newArray, this->c);
strcat(newArray, y.c);
delete[] c;
c = new char[strlen(newArray)];
this->c = newArray;
return *this;
}
//QUATRO
friend DynString operator+ (char* x, DynString& y) {
DynString newString;
newString.c = new char[strlen(x) + strlen(y.c) + 1];
strcpy(newString.c, x);
strcat(newString.c, y.c);
return newString;
}
//QUATRO
DynString& operator+ (char* x) {
char *newArray = new char[strlen(x) + strlen(this->c) + 1];
strcpy(newArray, this->c);
strcat(newArray, x);
delete[] c;
c = new char[strlen(newArray)];
this->c = newArray;
return *this;
}
//TRIO // QUATRO
DynString& operator= (DynString& x) {
char *newArray = new char[strlen(x.c) + 1];
strcpy(newArray, x.c);
delete[] c;
c = new char[strlen(newArray)];
this->c = newArray;
return *this;
}
};
int main()
{
DynString stringA("Hello");
DynString stringB(" Worlt");
//UNO
cout << stringA << stringB << std::endl;
//DUO
stringB[5] = 'd';
//TRIO
DynString stringC = stringA + stringB;
cout << stringC << std::endl;
DynString stringD;
//QUATRO
stringD = "The" + stringB + " Wide Web";
cout << stringD << std::endl;
system("pause");
return 0;
}
#1 楼
不要包含不必要的标头我们没有使用
<vector>
或<stdio.h>
,因此请将其删除。该类只需要<ostream>
而不是<iostream>
,并且我们更喜欢<cstring>
而不是<string.h>
来将标准函数放在其适当的命名空间中。 />这是一个坏习惯,会在较大的程序中引起问题。只是不要。添加一些编译器警告
通过
namespace std
,我得到了一些有用的诊断,值得关注: g++ -Weffc++
通过将
165851.cpp:33:39: warning: ‘DynString& DynString::operator+(DynString&)’ should return by value [-Weffc++]
DynString& operator+ (DynString& y) {
^
165851.cpp:54:34: warning: ‘DynString& DynString::operator+(char*)’ should return by value [-Weffc++]
DynString& operator+ (char* x) {
^
165851.cpp: In constructor ‘DynString::DynString(const char*)’:
165851.cpp:12:5: warning: ‘DynString::c’ should be initialized in the member initialization list [-Weffc++]
DynString(const char* input) {
^~~~~~~~~
165851.cpp: In copy constructor ‘DynString::DynString(const DynString&)’:
165851.cpp:19:5: warning: ‘DynString::c’ should be initialized in the member initialization list [-Weffc++]
DynString(const DynString& dynstring) {
^~~~~~~~~
165851.cpp: In function ‘int main()’:
165851.cpp:95:23: warning: ISO C++ forbids converting a string constant to ‘char*’ [-Wpedantic]
stringD = "The" + stringB + " Wide Web";
^~~~~~~
165851.cpp:95:33: warning: ISO C++ forbids converting a string constant to ‘char*’ [-Wpedantic]
stringD = "The" + stringB + " Wide Web";
^~~~~~~~~~~
更改为接受operator+
而不是const char*
,可以很容易地解决最后两个问题。 char*
上的警告是要根据operator+
来实现operator+
(后者返回引用,但前者是对象)。 />如果评估operator+=
会发生什么?在这两种情况下,内部指针都指向DynString() + DynString()
,但是您很高兴在两者上都调用NULL
-这是未定义的行为。以下是一些实际检查的代码:DynString(const DynString& other)
: c(nullptr)
{
if (other.c) {
c = new char[std::strlen(other.c) + 1];
std::strcpy(c, other.c);
}
}
但是总是分配内存可能更容易(更安全):
DynString(const char* input)
: c(new char[(input ? std::strlen(input) : 0) + 1];)
{
if (input) {
std::strcpy(c, input);
} else {
*c = 'DynString(DynString&& other)
: DynString()
{
std::swap(c, other.c);
}
';
}
}
然后所有方法都可以安全地假设
strlen
不为空。添加move构造函数
这很容易:
char& operator[](size_t i) {
return c[i];
}
const char& operator[](size_t i) const {
return c[i];
}
重载
c
允许常量和可变字符串对象:
char *newArray = new char[strlen(y.c) + strlen(this->c) + 1];
strcpy(newArray, this->c);
strcat(newArray, y.c);
delete[] c;
c = new char[strlen(newArray)];
this->c = newArray;
我相信
operator[]
比size_t
更适合作为索引类型。消除内存泄漏
示例程序泄漏:
int
主要原因是:
delete[] c;
c = new char[strlen(newArray)];
c = newArray;
如果您看到错误,则更明显从最后一行删除冗余
==13517== Memcheck, a memory error detector
==13517== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al.
==13517== Using Valgrind-3.12.0.SVN and LibVEX; rerun with -h for copyright info
==13517== Command: ./165851
==13517==
Hello Worlt
Hello World
The World Wide Web
sh: 1: pause: not found
==13517==
==13517== HEAP SUMMARY:
==13517== in use at exit: 47 bytes in 3 blocks
==13517== total heap usage: 12 allocs, 9 frees, 73,860 bytes allocated
==13517==
==13517== 11 bytes in 1 blocks are definitely lost in loss record 1 of 3
==13517== at 0x4C2C93F: operator new[](unsigned long) (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==13517== by 0x108FF3: DynString::operator+(DynString&) (165851.cpp:38)
==13517== by 0x108C62: main (165851.cpp:90)
==13517==
==13517== 18 bytes in 1 blocks are definitely lost in loss record 2 of 3
==13517== at 0x4C2C93F: operator new[](unsigned long) (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==13517== by 0x10915B: DynString::operator+(char*) (165851.cpp:59)
==13517== by 0x108CD5: main (165851.cpp:95)
==13517==
==13517== 18 bytes in 1 blocks are definitely lost in loss record 3 of 3
==13517== at 0x4C2C93F: operator new[](unsigned long) (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==13517== by 0x1091EF: DynString::operator=(DynString&) (165851.cpp:69)
==13517== by 0x108CE7: main (165851.cpp:95)
==13517==
==13517== LEAK SUMMARY:
==13517== definitely lost: 47 bytes in 3 blocks
==13517== indirectly lost: 0 bytes in 0 blocks
==13517== possibly lost: 0 bytes in 0 blocks
==13517== still reachable: 0 bytes in 0 blocks
==13517== suppressed: 0 bytes in 0 blocks
==13517==
==13517== For counts of detected and suppressed errors, rerun with: -v
==13517== ERROR SUMMARY: 3 errors from 3 contexts (suppressed: 0 from 0)
:public:
DynString& operator+=(const DynString& other)
{
char *newArray = new char[strlen(c) + strlen(other.c) + 1];
std::strcpy(newArray, c);
std::strcat(newArray, other.c);
delete[] c;
c = newArray;
return *this;
}
DynString operator+(const DynString& other) const
{
DynString newString(*this);
return newString += other;
}
第一次分配显然已泄漏,应删除该行代码。在其他几种方法中也存在相同的错误。
this->
的实现:我会这样写,从其他版本需要的
operator+
开始:DynString operator+(const char* x, const DynString& other) {
DynString newString(x);
return newString += other;
}
我们不需要
+=
,因为C风格的字符串将使用(非显式)构造函数提升为operator+(const char*)
。我们确实需要重载以将C样式的字符串作为第一个参数-但它不必是朋友,因为它可以是普通的非成员函数:#include <ostream>
#include <cstring>
class DynString {
private:
char *c;
public:
~DynString()
{
delete[] c;
}
DynString(const char* input = nullptr)
: c(new char[(input ? std::strlen(input) : 0) + 1])
{
if (input) {
std::strcpy(c, input);
} else {
*c = 'private:
DynString(const DynString& a, const DynString& b)
: c(new char[std::strlen(a.c) + std::strlen(b.c) + 1])
{
std::strcpy(c, a.c);
std::strcat(c, b.c);
}
public:
DynString operator+(const DynString& other) const
{
return DynString(*this, other);
}
';
}
}
DynString(const DynString& other)
: c(new char[std::strlen(other.c) + 1])
{
std::strcpy(c, other.c);
}
DynString(DynString&& other)
: DynString()
{
std::swap(c, other.c);
}
friend std::ostream& operator<<(std::ostream& lhs, const DynString& a)
{
return lhs << a.c;
}
char& operator[](size_t i)
{
return c[i];
}
const char& operator[](size_t i) const
{
return c[i];
}
DynString& operator+=(const DynString& other)
{
char *newArray = new char[strlen(c) + strlen(other.c) + 1];
std::strcpy(newArray, c);
std::strcat(newArray, other.c);
delete[] c;
c = newArray;
return *this;
}
DynString operator+(const DynString& other) const
{
DynString newString(*this);
return newString += other;
}
DynString& operator=(DynString other) {
std::swap(c, other.c);
return *this;
}
};
DynString operator+(const char* x, DynString& other) {
DynString newString(x);
return newString += other;
}
#include <iostream>
int main()
{
DynString stringA("Hello");
DynString stringB(" Worlt");
//UNO
std::cout << stringA << stringB << std::endl;
//DUO
stringB[5] = 'd';
//TRIO
DynString stringC = stringA + stringB;
std::cout << stringC << std::endl;
DynString stringD;
//QUATRO
stringD = "The" + stringB + " Wide Web";
std::cout << stringD << std::endl;
}
改进版本
此代码已经过测试,不会泄漏:
void swap(DynString& other)
{
std::swap(length, other.length);
std::swap(c, other.c);
}
DynString& operator+=(const DynString& other)
{
Dynstring newString(*this, other);
swap(newString);
return *this;
}
>使串联更有效
通过复制和附加来实现
DynString
效率低下,因为它为在附加期间立即释放的副本分配了内存。因此,我们可以重新考虑该方法并消除复制步骤。我会使用额外的构造函数来做到这一点:private:
std::size_t length; // not including terminator
char *c;
DynString(const DynString& a, const DynString& b)
: length(a.length + b.length),
c(new char[length + 1])
{
std::memcpy(c, a.c, a.length);
std::memcpy(c+a.length, b.c, b.length+1); // copies terminator
}
我们现在可以简化
operator+
,并根据新的operator+=
实现:private:
std::size_t length; // not including terminator
std::unique_ptr<char[]> c;
DynString(const DynString& a, const DynString& b)
: length(a.length + b.length),
c(std::make_unique<char[]>(length + 1))
{
std::memcpy(c.get(), a.c.get(), a.length);
std::memcpy(c.get()+a.length, b.c.get(), b.length+1); // copies terminator
}
记住字符串的长度
如果我们将长度存储为成员,我们可以使每种方法更有效,并且允许在字符串中嵌入NUL字符:
#include <memory>
class DynString {
private:
std::size_t length; // not including terminator
std::unique_ptr<char[]> c;
// Helper constructor - allocates but does not initialize
DynString(size_t length)
: length(length),
c(std::make_unique<char[]>(length + 1))
{}
DynString(const DynString& a, const DynString& b)
: DynString(a.length + b.length)
{
std::memcpy(c.get(), a.c.get(), a.length);
std::memcpy(c.get()+a.length, b.c.get(), b.length+1); // copies terminator
}
public:
DynString(const char* input = nullptr)
: DynString(input ? std::strlen(input) : 0)
{
if (input) {
std::memcpy(c.get(), input, length + 1);
} else {
c.get()[0] = 'q4312078q';
}
}
DynString(const DynString& other)
: DynString(other.length)
{
if (length != other.length)
c = std::make_unique<char[]>(other.length+1);
length = other.length;
std::memcpy(c.get(), other.c.get(), length + 1);
}
DynString(DynString&& other) noexcept
: DynString()
{
swap(other);
}
void swap(DynString& other) noexcept
{
std::swap(length, other.length);
std::swap(c, other.c);
}
friend std::ostream& operator<<(std::ostream& lhs, const DynString& a)
{
return lhs << a.c.get();
}
char& operator[](size_t i) noexcept
{
return c.get()[i];
}
const char& operator[](size_t i) const noexcept
{
return c.get()[i];
}
DynString& operator+=(const DynString& other)
{
DynString newString(*this, other);
swap(newString);
return *this;
}
DynString operator+(const DynString& other) const
{
return DynString(*this, other);
}
DynString& operator=(DynString other) noexcept
{
swap(other);
return *this;
}
};
依靠内存管理的标准库
代替管理自己的内存,我们可以使
operator+
成为唯一的指针:q4312078q
您会发现我们确实需要将对
c
的调用分散到需要指向内容的指针智能指针版本:
(仅是类;除上面的第一个“改进版本”外,其他所有内容均保持不变,除了其他包含项)
q4312078q
评论
\ $ \ begingroup \ $
让我批评您的评论:1. c * -header不保证将其符号限制在命名空间std中。他们只保证也把它们放在那里。 2.用operator + =来实现operator +对于此类来说效率极低。
\ $ \ endgroup \ $
–重复数据删除器
17年6月15日在13:50
\ $ \ begingroup \ $
@Deduplicator,我并不是要暗示标头不得在命名空间std之外声明任何内容。我确实发现,如果我可以明确说明函数的来源,这会使我的代码更清晰。我想我可能还认为这可以减少意外使用保留标识符的风险,但这可能是虚幻的!至于效率,您当然就在那里,但是我想在进一步优化之前专注于正确性(而现实世界中的实现则更进一步,例如SSO)。
\ $ \ endgroup \ $
– Toby Speight
17年6月15日14:00
\ $ \ begingroup \ $
这确实是足够的。但是这些进一步的优化多少都取决于要计算的字符串...
\ $ \ endgroup \ $
–重复数据删除器
17年6月15日在14:11
\ $ \ begingroup \ $
当使用命名空间std显然过于时尚时,我仍然觉得这一点令人信服。 stackoverflow.com/questions/1452721/…为什么要从第三方库重载标准库函数名?
\ $ \ endgroup \ $
–解毒
17年6月15日在19:16
\ $ \ begingroup \ $
@Pysis一个简单的变量数据或计数足以使编译器抱怨。
\ $ \ endgroup \ $
–Rakete1111
17年6月16日在11:28
#2 楼
不要包含您不使用的内容。您只能使用
<string.h>
和<stdio.h>
。虽然包括
<vector>
仅花费编译时间,但是包括<iostream>
可能会增加可执行文件的大小和启动/关闭时间。您应该避免
using namespace std;
这是一个困扰,只是出价以后该咬你了。为什么要“使用命名空间标准”;认为是不好的做法吗?很抱歉,您的评论似乎完全没有用。至少我无法从中提取任何有用的信息。因此,清除它们。
您的
DynString
似乎是对0终止的字符串的薄包装。您确定您将永远不需要嵌入式零,也不必充分利用可能值得缓存的长度吗? />原始拥有指针是个坏主意。它们本身不仅易于泄漏,而且异常情况甚至会变得更加艰辛。请考虑迁移到
std::unique_ptr
的免费抽象。您的
nullptr
处理是不一致的。 nullptr
UB是空字符串还是保留为单独的状态?除此之外,
nullptr
优于NULL
或0
。它不仅具有独特的类型,而且也不能与整数混淆。将
std::size_t
用于索引和大小。就是这样。您忘记在允许的位置标记函数
noexcept
。您的默认构造函数应标记为
constexpr
,或者分配一个长度为0的字符串。在
DynString(const char*)
中您计算长度分配适当数量的输入。为什么您不将其重用于高效的memcpy
而不是性能较低的strcpy
?至少允许将其用于隐式转换是有意义的。否则,您必须将其标记为
explicit
。DynString(const DynString&)
应该委托给DynString(const char*)
,而不是将所有内容都写遍。您缺少移动指针。
stream-output-operator不会修改第二个参数,因此应该通过常量引用来接受它。
您缺少
operator []
的常量重载。而且无论如何,索引应该是std::size_t
而不是int
。您的
operator+(DynString&)
(还有operator+(const char*)
)是一年级的混乱:它应该是按值返回一个新的
DynString
,而不是按引用返回其中一个参数。两个参数都应为常量。
您不应在其中分配第二次时间以泄漏它。此外,第二个分配也可能抛出...
它应该是一个朋友函数,因此可以在其第一个参数上进行转换,委托给连接两个
const char*
的私有方法。这样一来,您就可以实现两个变体,用const char*
替换其中一个参数以提高效率,而无需重复。为什么不重用您计算出的字符串长度?
memcpy
比strcpy
更有效。至少
operator+ (char* x, DynString& y)
没错,只有效率低。考虑添加
operator+=
(两种效率形式),分别根据operator+
和operator=
实现。您的
operator=
不应该接受左值引用。按值接受参数并使用复制和交换。这样一来,您还将丢失thememory-leak。您真的应该添加更多观察者,例如:
.data()
,.size()
,.begin()
和.end()
至少。修改后的代码,确定
nullptr
是UB ,并添加一些附加功能:#include <cstring>
#include <algorithm>
#include <utility>
#include <iterator>
#include <vector>
class DynString {
char *c;
DynString(std::picewise_construct_t, const char* a, const char* b) : c() {
auto na = std::strlen(a), nb = std::strlen(b);
c = new char[a + b + 1 > a ? a + b + 1 : SIZE_MAX];
std::copy_n(a, na, c);
std::copy_n(b, nb + 1, c + na);
}
template<class It, decltype((void)(*c = *std::declval<It>()))...>
DynString(std::forward_iterator_tag, It first, It last) : c() {
auto n = std::distance(first, last);
c = new char[0 <= n && n < SIZE_MAX ? std::size_t(n) + 1 : SIZE_MAX];
std::copy_n(first, std::size_t(n), c);
c[n] = 0;
}
template<class It, decltype((void)(*c = *std::declval<It>()))...>
DynString(std::input_iterator_tag, It first, It last) : c() {
std::vector<char> v(first, last);
swap({v.begin(), v.end()});
}
public:
DynString() : c(new char[1]{}) {}
DynString(const char* s) : DynString(s, s + std::strlen(s)) {}
DynString(const DynString& s) : DynString(s.c) {}
DynString(DynString&& s) : DynString() { swap(s); }
template<class It, decltype((void)DynString(std::iterator_traits<It>::iterator_category(), first, last))...>
DynString(It first, It last) : DynString(std::iterator_traits<It>::iterator_category(), first, last) {}
~DynString() { delete[] c; }
friend ostream& operator<<(ostream& lhs, const DynString& a) { return lhs << a.c; }
char& operator[](std::size_t i) noexcept { return c[i]; }
const char& operator[](std::size_t i) const noexcept { return c[i]; }
auto data() noexcept { return c; }
auto data() const noexcept { return c; }
auto begin() noexcept { return c; }
auto begin() const noexcept { return c; }
auto end() noexcept { return c + size(); }
auto end() const noexcept { return c + size(); }
auto rbegin() noexcept { return std::make_reverse_iterator(end()); }
auto rbegin() const noexcept { return std::make_reverse_iterator(end()); }
auto rend() noexcept { return std::make_reverse_iterator(begin()); }
auto rend() const noexcept { return std::make_reverse_iterator(begin()); }
auto size() const noexcept { return std::strlen(c); }
friend DynString operator+(const DynString& a, const DynString& b)
{ return {std::piecewise_construct, a.c, b.c}; }
friend DynString operator+(const char* a, const DynString& b)
{ return {std::piecewise_construct, a, b.c}; }
friend DynString operator+(const DynString& a, const char* b)
{ return {std::piecewise_construct, a.c, b}; }
DynString& operator+=(const DynString& s) { return *this += s.c; }
DynString& operator+=(const char* s) { return *this = *this + s; }
DynString& operator=(DynString s) { swap(s); return *this; }
void swap(DynString& o) noexcept { using std::swap; swap(c, o.c); }
};
评论
\ $ \ begingroup \ $
我想在回答中说一些关于嵌入式'\ 0'的内容,但我忘了。现在我不需要;-)
\ $ \ endgroup \ $
– Toby Speight
17年6月15日在13:51
#3 楼
这里的内存泄漏(在operator+
中): c = new char[strlen(newArray)];
this->c = newArray;
,因为
c
和this->c
之间没有区别。该代码将覆盖指向new
分配的内存的指针。#4 楼
我认为错过了其他答案的一件事:您正在使用strcat
,strcpy
和strlen
。是2017年,您正在编写C ++-绝对不要这样做。 而不是像在1978年一样编写C ++一样,请使用
strn*
函数家族:strncat
,strncpy
和一个强大的实现:Microsoft的strnlen
如果使用的是strnlen
(Linux,某些BSD等),则为GNU glibc
。此外,在C ++中,您还可以使用std::copy
和std::find
之类的漂亮函数。 这样做使您的代码本来就更安全(更不容易发生缓冲区溢出),更可预测和更可靠,并且更现代。
评论
\ $ \ begingroup \ $
注意:您也不必在C中使用那些函数的旧版本。
\ $ \ endgroup \ $
–大卫·康拉德(David Conrad)
17年6月16日在7:02
\ $ \ begingroup \ $
为什么不加倍努力,完全清除str *函数,并使用适当的C ++算法?即std :: copy(用于复制和连接),std :: find(用于长度)。诚然,如果存在,我会使用std :: strnlen;但事实并非如此。我想如果您在未知大小的缓冲区上操作std :: strlen是可以的(但那不应该发生)。
\ $ \ endgroup \ $
–康拉德·鲁道夫(Konrad Rudolph)
17年6月16日在9:17
\ $ \ begingroup \ $
@DavidConrad我首先是C程序员,一点都不是C ++程序员,所以这就是我对strn *情况的了解:)
\ $ \ endgroup \ $
–猫
17年6月16日在12:51
\ $ \ begingroup \ $
@Deduplicator对不起,什么?您是否只是说过有时可以使用这些功能的不安全且已弃用的版本?
\ $ \ endgroup \ $
–猫
17年6月16日在12:53
\ $ \ begingroup \ $
@cat:首先,只有MS弃用了它们,这很痛苦。其次,使用正确的工具完成工作,而实际上这绝不是这些功能。您是否曾经仔细研究过它们的API定义,尤其是strncpy和strncat?无论如何,str * cat遭受了画家Shlemiel的严重伤害! (使用strcpy仅表现出较弱的症状,如果有长度,则应使用std :: copy_n等。)
\ $ \ endgroup \ $
–重复数据删除器
17年6月16日在14:27
#5 楼
operator +实现有几个主要错误。请考虑以下情况,其中A,B和C在当前范围内是DynString类型:DynString& operator+ (DynString& y) {
char *newArray = new char[strlen(y.c) + strlen(this->c) + 1];
strcpy(newArray, this->c);
strcat(newArray, y.c);
delete[] c;
c = new char[strlen(newArray)];
this->c = newArray;
return *this;
}
现在考虑: >
或
DynString A = "foo";
DynString B = "bar";
A = A + B; //this example works and does what it looks like it should
这些示例具有意外的副作用。运行此块后,字符串存储以下值:
DynString A = "foo";
DynString B = "bar";
DynString C = A + B; //this example not work like it should
最后,我们返回引用,因此请考虑这种情况:
运行上述情况后,我们期望B是“ foobardude”,而我们对A的期望取决于我们是否意识到上一示例中的错误。我们应该期望A是“ foo”或“ foobar”,因为应该返回一个临时值。两者都不是,A将是“ foobardude”。如所写,该实现不允许在不更改变量原始值的情况下进行串联。
#6 楼
即使没有分配内存,析构函数也会尝试释放内存。也许创建一个布尔条件进行检查。评论
\ $ \ begingroup \ $
这不是缺陷。请记住,删除空指针是无操作的。
\ $ \ endgroup \ $
–重复数据删除器
17年6月15日在16:13
评论
关于const-ness,需要更多的方法:)从const DynString开始(我希望从const开始),您会发现operator []不起作用。您需要两个运算符,一个用于只读访问,一个用于修改。与operator =相同-目前,您不能在右侧使用const对象!只是为了避免混淆,您不需要两个版本的operator =-但需要将其参数设为const。而operator []确实需要两个版本:一个返回const char&,另一个返回char&。
@jvb为什么您希望他将从const开始? const适用于const之前的事物。 char * const x从右到左读取“ x是指向char的常量指针”。另一个示例:char const * x读取“ x是指向常量char的指针”。您建议以相反的顺序编写它只会阻止理解更复杂的情况。
@ doug65536我表示希望该源的作者可以开始使用const,因为找不到此关键字的单个实例。 -现在,请不要将此解释为使用建议。
@jvb啊,对不起,我误会了。