自定义string类

news2024/11/13 9:21:01

#include <iostream>  
#include <string>  
  
int main() {  
    std::string str = "Hello, World!";  
  
    // 使用 c_str() 将 std::string 转换为 C 风格字符串,并传递给 printf  
    printf("The string is: %s\n", str.c_str());  
  
    // 尝试修改返回的 C 风格字符串(错误示例,不应这样做)  
    // char* cstr = str.c_str();  
    // cstr[0] = 'h'; // 未定义行为,因为 cstr 指向的内存是常量  
  
    return 0;  
}
#include <iostream>
#include <string.h>
#include <cstring>
using namespace std;
class String {
public:
    String();
    String(const char *pstr);
    String(const String& rhs);
    String &operator=(const String &rhs);
    ~String();

    void print();
    size_t length() const;
    const char* c_str() const;

private:
    char *_pstr;
};

String::String() : _pstr(new char[1]) {
    _pstr[0] = '\0'; // 初始化为空字符串
}
String::String(const char *pstr) : _pstr(new char[strlen(pstr) +1]) {
    strcpy(_pstr,pstr);
}

String::String(const String& rhs) : _pstr(new char[strlen(rhs._pstr) + 1]) {
    strcpy(_pstr, rhs._pstr);
}
String& String::operator=(const String &rhs) {
    if (this != &rhs) {
        delete[] _pstr; // 释放旧资源
        _pstr = new char[strlen(rhs.c_str()) + 1]; // 分配新资源
        strcpy(_pstr, rhs.c_str()); // 复制内容
    }
    return *this; //String(const String& rhs) 返回对象的引用
}
const char* String::c_str() const {
    return this->_pstr;
}
size_t String::length() const {
    return strlen(_pstr);
}
void String::print() {
    std::cout << _pstr << std::endl;
}
String::~String() {
    if (_pstr) {
        delete[] _pstr;
    }
}


int main(){
    String str1("123");
    str1.print();

}


int main() {
	String str1("123");
	str1.print();
	std::cout << str1.length() << std::endl;
	return 0;
}
#include <iostream>
#include <vector>

template<typename T>
class SimpleStack {
public:
    // 添加元素到栈顶
    void push(T&& item) {
        data_.emplace_back(std::forward<T>(item));
    }

    // 移除栈顶元素并返回它的值
    T pop() {
        if (data_.empty()) {
            throw std::out_of_range("pop from empty stack");
        }
        T topItem = std::move(data_.back());
        data_.pop_back();
        return topItem;
    }

    // 返回栈顶元素,不移除
    const T& top() const {
        if (data_.empty()) {
            throw std::out_of_range("top from empty stack");
        }
        return data_.back();
    }

    // 检查栈是否为空
    bool empty() const {
        return data_.empty();
    }

    // 返回栈中的元素数量
    size_t size() const {
        return data_.size();
    }

private:
    std::vector<T> data_; // 使用std::vector作为底层容器存储数据
};

// 测试SimpleStack功能的小程序
int main() {
    SimpleStack<int> intStack;
    intStack.push(1);
    intStack.push(2);
    intStack.push(3);

    std::cout << "Top element is: " << intStack.top() << std::endl;
    std::cout << "Popped element is: " << intStack.pop() << std::endl;
    std::cout << "New top element is: " << intStack.top() << std::endl;

    return 0;
}

这个push函数的设计利用了C++11引入的右值引用(rvalue reference)和完美转发(perfect forwarding)技术。让我们一步一步来看这个函数的细节:

void push(T&& item) {
    data_.emplace_back(std::forward<T>(item));
}

1. **右值引用 (Rvalue Reference)**:
   - `T&& item` 这个声明表示`item`是一个右值引用,它可以绑定到一个右值(即临时对象)或者一个左值(普通的命名对象)。右值引用的存在主要是为了支持移动语义(move semantics),使得我们可以更高效地处理临时对象而不必进行拷贝构造。

2. **完美转发 (Perfect Forwarding)**:
   - `std::forward<T>(item)` 这个函数的作用是完美地将`item`转发给`data_.emplace_back`。如果`item`是一个右值(例如,当`push`被调用时传递了一个临时对象),`std::forward`会保留其右值性质;如果`item`是一个左值,那么它会被转发为左值。
   - 这种技术被称为“完美转发”,因为它允许我们将`push`函数的参数原封不动地传递给`emplace_back`,无论这个参数最初是以何种形式传递给`push`的。

3. **`emplace_back`**:
   - `std::vector` 类的一个成员函数,它在容器尾部直接构造一个新的元素。这比使用`push_back`更高效,因为`push_back`通常需要先创建一个临时对象再将其移动到容器中,而`emplace_back`则是在容器中直接构造对象,省去了临时对象的创建和移动。

为什么这么做?

- **性能**: 对于那些具有昂贵拷贝构造函数的对象,或者当传递的对象是临时对象时,使用右值引用和完美转发可以避免不必要的拷贝,从而提高性能。
- **灵活性**: 它使得函数能够接收任意类型的对象——无论是临时对象还是已经存在的对象——并且以最有效的方式处理它们。

总的来说,这种设计方式让我们的`push`函数更加通用且高效,尤其是在处理大型对象或者资源密集型对象时。

vector常用的函数:

`std::vector` 是C++标准库中的一个非常强大的容器,用于存储动态大小的数据集合。它提供了许多实用的成员函数,这些函数可以帮助我们方便地管理数据。下面是一些`std::vector`常用的成员函数及其用途简介:

1. **构造与初始化**
   - `vector()`: 默认构造函数,创建一个空的`vector`。
   - `vector(n, val)`: 创建一个含有`n`个`val`值的`vector`。
   - `vector(const vector& v)`: 复制构造函数,创建一个与`v`相同的新`vector`。
   - `vector(std::initializer_list<value_type> il)`: 使用一个初始化列表来初始化`vector`。

2. **容量**
   - `size()`: 返回`vector`中的元素数量。
   - `empty()`: 如果`vector`为空,则返回`true`。
   - `max_size()`: 返回`vector`可能达到的最大大小。
   - `capacity()`: 返回当前`vector`的容量,即它可以容纳的元素数量。
   - `reserve(size_type new_cap)`: 请求改变`vector`的容量,使其至少为`new_cap`。

3. **元素访问**
   - `operator[]`: 使用索引来访问元素。
   - `at(size_type pos)`: 访问指定位置的元素,并检查索引是否越界。
   - `front()`: 访问第一个元素。
   - `back()`: 访问最后一个元素。
   - `data()`: 返回指向容器中第一个元素的指针。

4. **修改器**
   - `push_back(const value_type& val)`: 在`vector`末尾添加一个元素。
   - `emplace_back(Args&&... args)`: 在`vector`末尾直接构造一个元素。
   - `pop_back()`: 移除最后一个元素。
   - `insert(iterator position, const value_type& val)`: 在`position`前插入一个元素。
   - `insert(iterator position, n, val)`: 在`position`前插入`n`个`val`值。
   - `insert(iterator position, std::initializer_list<value_type> il)`: 使用初始化列表来插入元素。
   - `erase(iterator position)`: 删除`position`所指向的元素。
   - `erase(iterator first, iterator last)`: 删除`[first, last)`区间内的元素。
   - `assign(std::initializer_list<value_type> il)`: 使用初始化列表重置`vector`的内容。
   - `clear()`: 移除所有元素。

5. **交换与释放**
   - `swap(vector& v)`: 与另一个`vector`交换内容。
   - `shrink_to_fit()`: 尝试减小`vector`的容量以匹配它的大小。

6. **分配器**
   - `allocator_type get_allocator()`: 返回`vector`使用的分配器。

7. **迭代器**
   - `begin()` 和 `end()`: 返回指向`vector`开始和结束位置的迭代器。
   - `cbegin()` 和 `cend()`: 返回指向`vector`开始和结束位置的常量迭代器。
   - `rbegin()` 和 `rend()`: 返回指向`vector`反向开始和结束位置的逆向迭代器。
   - `crbegin()` 和 `crend()`: 返回指向`vector`反向开始和结束位置的常量逆向迭代器。

以上就是`std::vector`的一些基本功能概述。每个函数都有其特定的用途,在不同的场景下选择合适的函数可以有效地管理和操作数据.

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2109598.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

网络层 V(IPv6)【★★★★★★】

一、IPv6 的特点 IP 是互联网的核心协议。现在使用的 IP&#xff08;即 IPv4 ) 是在 20 世纪 70 年代末期设计的。互联网经过几十年的飞速发展&#xff0c;到 2011 年 2 月&#xff0c;IPv4 的地址已经耗尽&#xff0c; ISP 已经不能再申请到新的 IP 地址块了。我国在 2014 年…

全能与专精:探索未来AI模型的发展趋势与市场潜力

文章目录 每日一句正能量前言AI模型的全面评估和比较AI模型的专精化和可扩展性AI模型的合理使用和道德规范后记 每日一句正能量 一个人&#xff0c;如果没有经受过投资失败的痛楚&#xff0c;又怎么会看到绝望之后的海阔天空。很多时候&#xff0c;经历了人生中最艰难的事&…

告别繁琐切换,可道云teamOS让企业微信和钉钉无缝对接,爽到飞起

在当今快节奏的工作环境中&#xff0c;企业对于高效办公工具的需求日益增强。特别是企业微信和钉钉的普及&#xff0c;已成为许多企业日常沟通协作的基石。然而&#xff0c;传统企业网盘与这些平台的割裂&#xff0c;常常让工作流程变得繁琐。 幸运的是&#xff0c;teamOS的出…

vs2019编译opencv+contribute+gpu

1、提前准备 vs2019、opencv4.4.0、opencv-contribute4.4.0、CUDA Toolkit 11.8&#xff08;不能高于自己电脑的CUDA版本&#xff09;、CUDNN8.9.6 ps&#xff1a;先提前准备环境 1&#xff09;cmd中查看&#xff1a;nvidia-smi查看自己的显卡信息&#xff0c;不存在下述信息…

文本匹配任务(下)

文本匹配任务 1.文本匹配-深度学习1.1表示型1.1.1训练方式一1.1.2训练方式二&#xff08;Triplet Loss&#xff09; 1.2交互型1.3交互型和表示型对比 2.对比学习2.1图像中2.2NLP中 3.真实场景-海量向量查找3.1CD树3.1.1空间切割3.1.2Annoy 1.文本匹配-深度学习 简介&#xff1…

EasyExcel 文件导出 - 合并某些列值相同的行

文章目录 EasyExcel 文件导出 - 合并某些列值相同的行最终效果实现思路创建单元格合并的策略类使用 EasyExcel 文件导出 - 合并某些列值相同的行 在数据处理与文件导出的过程中&#xff0c;我们常常会遇到各种特定的需求。今天&#xff0c;我们就来探讨一下使用 EasyExcel 进行…

VsCode 联想路径配置

问题&#xff1a;举一个例子&#xff0c;引入文件 import store from ‘./store’&#xff0c;在输入 ./st 后会提示store。 配置路径别名后 webpack: {// 配置别名alias: {// 使用 表示 src 文件所在路径: path.resolve(__dirname, src)}}项目配置路径后输入 import store f…

JVM面试真题总结(一)

文章收录在网站&#xff1a;http://hardyfish.top/ 文章收录在网站&#xff1a;http://hardyfish.top/ 文章收录在网站&#xff1a;http://hardyfish.top/ 文章收录在网站&#xff1a;http://hardyfish.top/ Java主要是解释执行还是编译执行?请说明理由 Java既是解释执行的…

828华为云征文|部署私有云和文档管理系统 Kodcloud

828华为云征文&#xff5c;部署私有云和文档管理系统 Kodcloud 一、Flexus云服务器X实例介绍1.1 云服务器介绍1.2 产品优势1.3 对比Flexus L实例和ECS 二、Flexus云服务器X实例配置2.1 重置密码2.2 服务器连接2.3 安全组配置 三、部署 Kodcloud3.1 Kodcloud 介绍3.2 Docker 环境…

Google数字车钥匙:引领汽车互动新纪元

在科技的浪潮中&#xff0c;Digital Car Key正以一种全新的姿态重塑我们与汽车的互动。告别传统的钥匙束缚&#xff0c;只需轻触手机应用&#xff0c;即可轻松掌控汽车。这一创新解决方案不仅大幅提升了安全性&#xff0c;更带来了前所未有的便捷&#xff0c;无论是城市通勤还是…

SSM校园兼职网站—计算机毕业设计源码25557

摘 要 当今人类社会已经进入信息全球化和全球信息化、网络化的高速发展阶段。丰富的网络信息已经成为人们工作、生活、学习中不可缺少的一部分。人们正在逐步适应和习惯于网上贸易、网上购物、网上支付、网上服务和网上娱乐等活动&#xff0c;人类的许多社会活动正在向网络化发…

Kafka【九】如何实现数据的幂等性操作

为了解决Kafka传输数据时&#xff0c;所产生的数据重复和乱序问题&#xff0c;Kafka引入了幂等性操作&#xff0c;所谓的幂等性&#xff0c;就是Producer同样的一条数据&#xff0c;无论向Kafka发送多少次&#xff0c;kafka都只会存储一条。注意&#xff0c;这里的同样的一条数…

C++ 在给定斜率的线上找到给定距离处的点(Find points at a given distance on a line of given slope)

给定二维点 p(x 0 , y 0 )的坐标。找到距离该点 L 的点&#xff0c;使得连接这些点所形成的线的斜率为M。 例子&#xff1a; 输入&#xff1a; p (2, 1) L sqrt(2) M 1 输出&#xff1a;3, 2 1, 0 解释&#xff1a; 与源的距离为 sqrt(2) &#x…

【C++二分查找】2594. 修车的最少时间

本文涉及的基础知识点 C二分查找 LeetCode2594. 修车的最少时间 给你一个整数数组 ranks &#xff0c;表示一些机械工的 能力值 。ranksi 是第 i 位机械工的能力值。能力值为 r 的机械工可以在 r * n2 分钟内修好 n 辆车。 同时给你一个整数 cars &#xff0c;表示总共需要修…

论文阅读笔记《面向集群协同的两点相对定位技术》

邓廷祥,任鹏,程甲,等.面向集群协同的两点相对定位技术[J].兵工学报,2023,44(S2):22-34. 摘要 无人机精确定位的三个难题&#xff1a; GNSS难以提供稳定准确的位置信息、难以部署辅助锚点、传统的相对定位方法大多存在节点数量限制。 本文针对上述问题&#xff0c;提出了一种GN…

Django 中的用户界面 - 创建速度计算器

在 Django 中创建一个用户界面来计算速度&#xff0c;可以通过以下步骤完成。这个速度计算器将允许用户输入距离和时间&#xff0c;计算并显示速度。 一、问题背景 一位 Django 新手希望使用 Django 构建一个用户界面&#xff0c;以便能够计算速度&#xff08;速度 距离/时间…

为什么 2!=false 和 2!=true 返回的都是true

前言 今天突然想起一个奇怪的问题&#xff0c;记录一下&#xff0c;我在控制台执行内容如下&#xff1a; 由上图可见&#xff0c;2 ! false 和 2 ! true 返回的值竟然都是true&#xff0c;那么为什么呢&#xff0c;请看下文&#xff1a; 1 ! 操作符的作用 ! 是“不等于”操作…

用了这个编程助手,“数学建模”真的太简单了~

目录 一、ChatGPT在数学建模中的价值1、学习和指导2、模型评估和改进3、算法设计和优化4、解释和文档生成 二、作为编程手如何正确使用ChatGPT1、阅读代码及优化代码2、执行脚本3、生成单测 三、编程手备战建模大赛的一些建议1、明确&#xff1a;如何去问一个问题2、程序设计能…

生日贺卡录放音芯片,多段音频录音ic生产厂商,NVF04M-32minute

可以录音播放的生日贺卡与传统的纸质贺卡相比&#xff0c;它有着创意以及个性的特点&#xff0c;仅需少量的电子元器件&#xff0c;即可实现录音功能&#xff0c;搭配上文字&#xff0c;让声音存储在生日贺卡里&#xff0c;让贺卡也变得有温度&#xff0c;祝福我想亲口对TA说。…

【计算机网络】描述TCP建立连接与断开的过程

一、TCP连接的建立与断开 1、建立连接——三次握手 1、A的TCP向B发出连接请求报文段 其首部中的同步位SYN 1&#xff0c;并选择序号seq x&#xff0c;表明传送数据时的第一个数据字节的序号是 x 2、B的TCP收到连接请求报文段后&#xff0c;如同意&#xff0c;则发回确认。 B …