写Foo类的目的,用以测试打印构造、析构,因为普通的内置变量无法输出构造、析构过程。
Foo.h
#ifndef FOO_H__
#define FOO_H__
#include <string>
class Foo
{
public:
Foo(std::string s);
~Foo();
std::string getData() const { return data; }
void setData(std::string val) { data = val; }
private:
std::string data;
};
#endif // Foo_h__
Foo.cpp
#include "Foo.h"
#include <iostream>
using namespace std;
Foo::Foo(string arg) : data(arg)
{
cout << "Foo() 构造函数 " << data << endl;
}
Foo::~Foo()
{
cout << "~Foo() 析构函数 " << data << endl;
}
StrBlob.h
#ifndef STRBLOB_H__
#define STRBLOB_H__
#include <vector>
#include <string>
#include <initializer_list>
#include <memory>
#include <stdexcept>
using namespace std;
class StrBlobPtr;
class StrBlob
{
friend class StrBlobPtr;
// 重载输出运算符
// friend ostream& operator<<(ostream & os, const StrBlob & item);
public:
typedef vector<string>::size_type size_type;
StrBlob();
StrBlob(initializer_list<string> il);
/*
这里使用了默认的拷贝、赋值
拷贝:shared_ptr会递增其引用计数
赋值:左侧的shared_ptr引用计数递减,右侧的shared_ptr引用计数递增
如何销毁?
当引用计数为0时,所指向对象自动销毁
*/
size_type size() const;
bool empty() const;
void push_back(const string& t);
void pop_back();
string& front();
const string& front() const;
string& back();
const string& back() const;
// 提供给StrBlobPtr的接口
StrBlobPtr begin();
StrBlobPtr end();
StrBlobPtr begin() const;
StrBlobPtr end() const;
private:
shared_ptr<vector<string>> data;
void check(size_type i, const string& msg) const;
};
class StrBlobPtr {
friend bool eq(const StrBlobPtr& a, const StrBlobPtr& b);
public:
StrBlobPtr();
StrBlobPtr(StrBlob& a, size_t sz = 0);
StrBlobPtr(const StrBlob& a, size_t sz = 0);
string& deref() const;
StrBlobPtr& incr();//前缀递增
StrBlobPtr& decr();//前缀递减
private:
// 若数组下标没超边界,返回一个指向 vector的shared_ptr
shared_ptr<vector<string>> check(size_t i, const string& msg) const;
weak_ptr<vector<string>> wptr;//使用weak_ptr可防止底层vector被销毁的问题
size_t curr; // 数组中当前位置
};
bool eq(const StrBlobPtr& lhs, const StrBlobPtr& rhs);
bool neq(const StrBlobPtr& lhs, const StrBlobPtr& rhs);
// ostream& operator<<(ostream& os, const StrBlob& item);
#endif // StrBlob_h__
StrBlob.cpp
#include "StrBlob.h"
using namespace std;
//ostream& operator<<(ostream& os, const StrBlob& item)
//{
// if (item.size() > 0)
// os << item.front() << " " << item.back();
// else
// os << "item 为空";
// return os;
//}
StrBlob::StrBlob() :data(make_shared <vector<string>>())
{
}
StrBlob::StrBlob(initializer_list<string> il) :data(make_shared <vector<string>>(il))
{
}
StrBlob::size_type StrBlob::size() const
{
return data->size();
}
std::string& StrBlob::front()
{
check(0, "front on empty StrBlob");
return data->front();
}
const std::string& StrBlob::front() const
{
check(0, "front on empty StrBlob");
return data->front();
}
std::string& StrBlob::back()
{
check(0, "back on empty StrBlob");
return data->back();
}
const std::string& StrBlob::back() const
{
check(0, "front on empty StrBlob");
return data->back();
}
StrBlobPtr StrBlob::begin()
{
return StrBlobPtr(*this);
}
StrBlobPtr StrBlob::begin() const
{
return StrBlobPtr(*this);
}
StrBlobPtr StrBlob::end()
{
auto ret = StrBlobPtr(*this, data->size());
return ret;
}
StrBlobPtr StrBlob::end() const
{
auto ret = StrBlobPtr(*this, data->size());
return ret;
}
bool StrBlob::empty() const
{
return data->empty();
}
void StrBlob::push_back(const string& t)
{
data->push_back(t);
}
void StrBlob::pop_back()
{
check(0, "pop_back on empty StrBlob");
data->pop_back();
}
void StrBlob::check(size_type i, const string& msg) const
{
if (i >= data->size())
throw out_of_range(msg);
}
StrBlobPtr::StrBlobPtr(StrBlob& a, size_t sz /*= 0*/) : wptr(a.data), curr(sz)
{
}
StrBlobPtr::StrBlobPtr() : curr(0)
{
}
StrBlobPtr::StrBlobPtr(const StrBlob& a, size_t sz /*= 0*/) : wptr(a.data), curr(sz)
{
}
std::string& StrBlobPtr::deref() const
{
auto p = check(curr, "dereference past end");
return (*p)[curr];
}
StrBlobPtr& StrBlobPtr::incr()
{
check(curr, "increment past end of StrBlobPtr");
++curr;
return *this;
}
StrBlobPtr& StrBlobPtr::decr()
{
--curr;
check(curr, "decrement past begin of StrBlobPtr");
return *this;
}
std::shared_ptr<std::vector<std::string>> StrBlobPtr::check(size_t i, const string& msg) const
{
auto ret = wptr.lock();
if (!ret)
throw std::runtime_error("unbound StrBlobPtr");
if (i >= ret->size())
throw std::out_of_range(msg);
return ret;
}
inline
bool eq(const StrBlobPtr& lhs, const StrBlobPtr& rhs)
{
auto left = lhs.wptr.lock(), right = rhs.wptr.lock();
if (left == right) // 两指针为空或指向相同的元素
return (!left || lhs.curr == rhs.curr);
else
return false;
}
bool neq(const StrBlobPtr& lhs, const StrBlobPtr& rhs)
{
return !eq(lhs, rhs);
}
main.cpp
#include <iostream>
#include <memory>
#include <string>
#include <vector>
#include "Foo.h"
#include "StrBlob.h"
//#include "my_StrBlob.h"
using namespace std;
//int bbb = 333;
shared_ptr<Foo> factory(string arg)
{
return make_shared<Foo>(arg);
}
shared_ptr<Foo> use_factory(string arg)
{
shared_ptr<Foo> p = factory(arg);
cout << "use_factory()函数结束" << endl;
return p;
}
shared_ptr<int> clone(int p)
{
// return new int(p); // 无法隐式转换为 shared_ptr<int>
return shared_ptr<int>(new int(p)); // 显式创建
}
void process(shared_ptr<Foo> ptr)
{
}
#if 1
struct destination {
};
struct connection {
};
connection connect(destination* des) {
cout << "connect() ..." << endl;
return connection();
}
void disconnect(connection con) {
cout << "disconnect()..." << endl;
};
void f(destination& d) {
connection c = connect(&d);
// 如果忘记 disconnect, 就无法关闭 c
}
void end_connection(connection* p) {
disconnect(*p);
}
void f2(destination& d) {
connection c = connect(&d);
shared_ptr<connection> p(&c, end_connection);
// 如果忘记 disconnect 或者异常, 也能自动关闭 c
}
void f3(destination& d)
{
connection c = connect(&d);
unique_ptr<connection, decltype(end_connection)*> p(&c, end_connection);
// 如果忘记 disconnect 或者异常, 也能自动关闭 c
}
#endif
void test_allocator()
{
// 分配5个未初始化的string,即未构造的
int n = 5;
allocator<string> alloc;
auto const p = alloc.allocate(n);
auto q = p; // 不使用最初始的指针,便于以后释放
// 构造
alloc.construct(q++, 10, 'c');
alloc.construct(q++);
alloc.construct(q++, "hi");
cout << *p << endl; // 正确, cccccccccc
cout << *q << endl; // 灾难,指向未构造的内存
// 析构
while (q != p)
alloc.destroy(--q); // 释放构造的string
// 释放内存
alloc.deallocate(p, n);
}
void test_allocator_rewrite_427() {
allocator<string> alloc;
auto const p = alloc.allocate(100);
string s;
string* q = p;
while (cin >> s && q != p + 100)
alloc.construct(q++, s);
const size_t size = q - p;
for (size_t i = 0; i < size; ++i)
cout << p[i] << " ";
cout << endl;
while (q != p)
alloc.destroy(--q);
alloc.deallocate(p, 100);
}
int main()
{
#if 0
shared_ptr<string> p1 = make_shared<string>("hello");
cout << *p1 << endl; // "hello"
*p1 = "";
cout << *p1 << endl; // ""
if (p1 && p1->empty())
*p1 = "hi";
cout << *p1 << endl; // "hi"
#endif
/*
以下用法有问题
一般是使用堆空间才会使用智能指针
而下面的用法是直接使用,根本用不着智能指针
智能指针用法:
1)new
2) make_shared<T>()
*/
#if 0
shared_ptr<string> p2;
if (p2 && p2->empty()) {
*p2 = "world";
}
cout << *p2 << endl; // error
#endif
#if 0
shared_ptr<int> p3 = make_shared<int>(42);
cout << *p3 << endl; // 42
shared_ptr<string> p4 = make_shared<string>(10, '9');
cout << *p4 << endl; // 9999999999
shared_ptr<int> p5 = make_shared<int>();
cout << *p5 << endl; // 0
auto p6 = make_shared<vector<string>>();
for (auto s : *p6)
cout << s << " ";
cout << endl;
shared_ptr<int> p = make_shared<int>(42);
cout << p.use_count() << endl;
cout << p.unique() << endl;
auto q(p);
cout << p.use_count() << endl;
cout << p.unique() << endl;
auto r = make_shared<int>(58);
r = q;
cout << *r << " " << r.use_count() << endl;
#endif
#if 0
use_factory(42);
cout << "main 函数结束" << endl;
#endif
#if 0
// 12.1.1练习 使用 StrBlob
StrBlob b1;
cout << "b1: " << b1 << endl;
{
StrBlob b2 = { "a","an","the" };
cout << "b2: " << b2 << endl;
b1 = b2;
cout << "b1: " << b1 << endl;
b2.push_back("about");
cout << "b1: " << b1 << endl;
cout << "b2: " << b2 << endl;
}
cout << "b1: " << b1 << endl;
//cout << "b2: " << b2 << endl;
#endif
#if 0
// shared_ptr与new结合使用
//shared_ptr<double> p1;
//p1 = new double(2.2); // 错误, 如要使用,必须直接初始化
//shared_ptr<int> p1 = new int(1024); // 错误,如要使用,必须直接初始化
// shared_ptr<int> p2(new int(42)); // 正确
#endif
#if 0
// 正确使用
shared_ptr<Foo> p(new Foo(1)); // 智能指针+new
process(p);
cout << p->getData() << endl;
#endif
#if 0
Foo* f(new Foo(1)); // 一个普通指针
// class“std::shared_ptr<Foo>”的构造函数声明为“explicit”
// 无法将参数 1 从“Foo *”转换为“std::shared_ptr<Foo>”
// process(f);
process(shared_ptr<Foo>(f)); // 能过,但内存在函数内会被释放
cout << f->getData() << endl;
/* 可以看出内存已被销毁
Foo() 构造函数
~Foo() 析构函数
-572662307
*/
#endif
#if 0
// 智能指针使用get()函数能返回一个内置指针
// 目的:向不能使用智能指针的代码传递一个内置指针,但不允许其delete
shared_ptr<Foo> p(new Foo("a"));
cout << p.use_count() << " " << p->getData() << endl;
Foo* q = p.get();
{
cout << "in..." << p.use_count() << " " << p->getData() << endl;
shared_ptr<Foo>(q); // OK???在退出作用域时并未触发析构
// shared_ptr<Foo> p2 = shared_ptr<Foo>(q); // 错误
// p2->setData("b");
cout << "out..." << p.use_count() << " " << p->getData() << endl;
}
cout << p.use_count() << " " << p->getData() << endl;
#endif
#if 0
shared_ptr<int> p(new int(42));
// p = new int(1024); // 错误:不能将一个指针赋予shared_ptr
cout << "p: " << *p << endl;
p.reset(new int(1024)); // 正确
cout << "p: " << *p << endl;
shared_ptr<int> q(p); // 增加一个引用测试以下代码
if (!p.unique()) // 如果我不是唯一,分配新的拷贝,以免q无法使用
p.reset(new int(222));
*p += 111;
cout << "p:" << *p << endl;
cout << "q:" << *q << endl; // 不影响q的数据使用和变化
#endif
#if 0
{
shared_ptr<Foo> p(new Foo("a"));
process(shared_ptr<Foo>(p.get()));
cout << "---" << endl;
}
cout << "}" << endl;
#endif
#if 0
// unique_ptr
// unique_ptr<double> p1;
// p1 = new int(12); // 错误,要直接初始化
// unique_ptr<int> p2(new int(42)); // 正确
unique_ptr<string> p1(new string("hello"));
unique_ptr<string> p2(p1); // 不支持拷贝
// unique_ptr<string> p3;
// p3 = p2; // 不支持赋值
cout << *p1 << endl;
// unique_ptr<string> p2(p1.release());
// cout << *p1 << endl; // 如果p1被释放,无法判断
cout << *p2 << endl;
// unique_ptr<string> p3(new string("Trex"));
unique_ptr<string> p3; // 未初始为empty
if (p3)
cout << "p3:" << *p3 << endl;
p2.reset(p3.release());
if (p2)
cout << *p2 << endl;
#endif
#if 0
destination d;
// f(d);
// f2(d);
f3(d);
#endif
#if 0
// weak_ptr 配合 shared_ptr使用
shared_ptr<int> p = make_shared<int>(42);
weak_ptr<int> wp(p); // weak_ptr
cout << p.use_count() << endl; //1
cout << wp.use_count() << endl; //1
if (shared_ptr<int> np = wp.lock()) {
cout << *np << endl;
}
#endif
#if 0
StrBlob b;
b.push_back("aaa");
b.push_back("bbb");
b.push_back("ccc");
for (StrBlobPtr it = b.begin(); neq(it, b.end()); it.incr())
cout << it.deref() << " ";
cout << endl;
const StrBlob c = {"Hello", "World", "!"};
for (auto it = c.begin(); neq(it, c.end()); it.incr())
cout << it.deref() << " ";
cout << endl;
#endif
#if 0
size_t n = 3;
int* p = new int[n] {1,2,3,4};
for (int* q = p; q != p + n; ++q)
cout << *q << " ";
cout << endl;
#endif
#if 0
// typedef int arrT[42];
const int n = 42;
typedef int arrT[n];
int* p = new arrT{1,2,3,4,5};
cout << sizeof(arrT) << endl;
cout << sizeof(int) << endl;
cout << sizeof(arrT)/sizeof(int) << endl;
for (int* q = p; q != p + n && *q != 0; ++q)
cout << *q << " ";
cout << endl;
#endif
#if 0
unique_ptr<int[]> up(new int[10]);
for (size_t i = 0; i != 10; ++i)
up[i] = i;
for (size_t i = 0; i != 10; ++i)
cout << up[i] << " " << endl;
cout << endl;
up.release();
#endif
#if 0
cout << sizeof(int) << endl;
cout << sizeof(long) << endl;
cout << sizeof(long long) << endl;
#endif
#if 0
const char* c1 = "Hello ";
const char* c2 = "World";
char* r = new char[strlen(c1)+strlen(c2)+1];
strcpy(r, c1);
strcat(r, c2);
cout << r << endl;
string s1 = "hello ";
string s2 = "world";
strcpy(r, (s1 + s2).c_str());
cout << r << endl;
delete[] r;
#endif
#if 0
char* r = new char[10];
int len = 0;
char c;
while (cin.get(c)) {
if (isspace(c))
break;
r[len++] = c;
if (len == 10) {
cout << "达到数组容量上限" << endl;
break;
}
}
r[len] = 0;
cout << r << endl;
delete[] r;
#endif
// test_allocator();
test_allocator_rewrite_427();
return 0;
}
在使用及编写的过程了遇到了一个问题
就是inline问题
如果eq在.cpp写了inline, 则neq无论在.h和.cpp中都无法inline,没有想明白,我用的编译器是VS2022,X64
有知道的望告之,不胜感激!