C++Primer 中文第五版(第12章代码记录)

写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
有知道的望告之,不胜感激!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
《C Primer》是一本针对C语言初学者的经典教材,第五版的第六主要介绍了函数的基本概念和用法。 在第六中,教材首先介绍了函数的定义和调用。函数是具有独立功能的代码块,可以通过函数名来调用。函数由函数头、参数、函数体和返回值组成。函数头包括函数类型、函数名和参数类型,参数用于接收传递给函数的值,返回值用于将结果返回给调用者。 接着,教材详细介绍了函数的参数传递方式,包括按值传递、按引用传递和按指针传递。按值传递是指将参数的值复制给形参,按引用传递是指将参数的引用传递给形参,而按指针传递是将参数的地址传递给形参。不同的传递方式在函数内部对参数进行操作时,会对应不同的结果。 此外,教材还讲解了函数的返回值和函数的调用顺序。函数的返回值类型由函数头中的类型确定,可以是任意类型。当函数需要返回多个值时,可以使用结构体或指针进行返回。函数的调用顺序决定了函数执行的顺序,即哪个函数先执行,哪个函数后执行。 在函数的实现过程中,教材介绍了函数的定义和声明、局部变量和全局变量、递归等内容。通过这些知识点的学习,读者可以了解到函数的具体细节和一些实践技巧。 总的来说,第五版的第六通过清晰的语言和丰富的例子,循序渐进地讲解了函数的基本概念和用法。学完这一,读者将能够理解函数的定义、调用、参数传递、返回值和实现等方面的知识,为之后的学习和实践打下坚实的基础。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值