智能指针(C++11)

news2024/11/16 23:42:25

在这里插入图片描述

行到水穷处,坐看云起时。

文章目录

  • 简介
  • 内存泄漏
    • 内存泄漏分类
    • 内存泄漏检测工具
  • RAII
  • 智能指针原理
  • 智能指针使用
    • std::auto_ptr
    • std::unique_ptr
    • std::shared_ptr
      • std::shared_ptr循环引用
    • std::weak_ptr
  • 总结


简介

C++智能指针是在C++11标准引入的一项重要功能,用于改进内存管理和避免一些与传统的原始指针相关的常见问题。例如在C++中,程序员通常需要手动分配和释放内存,这可能导致一些常见问题,如内存泄漏、释放后的悬挂指针和多次释放相同的内存,而这些问题通常由人为的错误引起,因此引入智能指针是为了解决这些问题。

C++11标准引入了std::shared_ptrstd::unique_ptrstd::weak_ptr等智能指针类型,以提供更安全和便捷的内存管理方式。这些智能指针是C++标准库的一部分,可以自动跟踪资源的生命周期,当不再需要时自动释放资源。

内存泄漏

内存泄漏是指程序在动态分配内存后,却没有释放这些内存,并且失去了对这些内存的所有指向。这意味着这些内存块将一直被程序占用,直到程序结束,因为它们无法被操作系统的内存管理系统回收。并且内存泄漏还可能会导致如下问题:

  • 耗尽可用内存:内存泄漏会逐渐占用系统内存,最终导致可用内存耗尽。当内存不再可用时,系统可能会变得非常缓慢,甚至崩溃。

  • 性能下降:即使没有耗尽所有可用内存,内存泄漏也会导致程序性能下降。内存泄漏的内存分配会导致程序变得越来越慢,因为它必须不断地分配更多的内存,而无法释放不再使用的内存。

  • 不稳定性:内存泄漏可能导致程序不稳定,崩溃或出现未定义的行为。这可能会严重影响应用程序的可靠性,尤其是长时间运行的服务器应用程序。

  • 难以调试:内存泄漏通常不会引发直接的错误消息,而是在运行时逐渐积累。因此,发现和调试内存泄漏通常是一项棘手的任务。它可能需要使用专门的工具和技术来识别和修复。

  • 资源泄漏:除了内存泄漏,资源泄漏(如文件句柄、数据库连接等)也可能发生,从而导致系统无法访问重要资源。

内存泄漏是程序中常见的编程错误,特别是在使用动态内存分配时。在编程中,我们在使用指针得到便利的同时, 也不得不时刻警惕着内存泄漏。使用指针时一不注意就很容易照成内存泄漏,防不胜防。为了避免内存泄漏,在编程时应该谨慎管理内存。因此使用智能指针来确保及时释放不再使用的内存就会是一个非常好的方案。此外,定期进行内存泄漏检测和性能分析也是发现和解决内存泄漏问题的重要手段。

在这里插入图片描述

内存泄漏分类

内存泄漏可以分为多种类型,具体取决于泄漏的原因和发生的情况。如下:

类型说明
动态内存泄漏未释放分配的内存最常见的动态内存泄漏类型,它发生在程序分配了动态内存(例如使用 new 或 malloc),但未在之后释放这些内存(使用 delete 或 free)。还有就是失去指向内存的指针,在分配内存后,如果指针被重新分配或丢失,将无法释放分配的内存也会造成内存泄漏。
资源泄漏如未关闭打开的文件句柄,导致资源泄漏。未关闭数据库连接,可能会占用数据库服务器资源。未关闭网络连接,可能会导致系统资源耗尽。
循环引用如在使用智能指针(如 std::shared_ptr)时,如果存在循环引用,可能导致资源不被释放。这通常需要使用 std::weak_ptr 来解决。
未释放的资源如未解锁的互斥锁,可能会导致其他线程无法访问共享资源。未关闭的操作系统内核对象(例如,信号量、共享内存等)。
循环引用如当对象中包含回调函数,回调函数持有对象的引用,并且对象也持有回调函数的引用时,可能导致循环引用。

内存泄漏检测工具

检测内存泄漏是确保程序在运行时不会浪费内存的重要任务。有必要的话可以使用如下的一些第三方工具来帮助检测内存泄漏。

  1. Valgrind:Valgrind 是一种强大的开源工具,可用于检测内存泄漏和其他内存错误。它支持多种平台,包括Linux和macOS。使用Valgrind的memcheck工具可以检测内存泄漏。

方法:

  1. 安装 Valgrind(如果尚未安装)。
  2. 在终端中使用以下命令运行程序:valgrind --leak-check=full ./your_program。
  3. Valgrind将输出关于内存泄漏的详细信息,包括泄漏的位置和大小。
  1. ASAN(AddressSanitizer):ASAN是Clang和GCC的一个特性,可用于检测内存错误,包括内存泄漏。它集成在编译器中,可以通过编译选项启用。

方法

  1. 使用编译器选项 -fsanitize=address 编译你的程序。
  2. 运行你的程序。
  3. ASAN将在检测到内存泄漏时输出详细信息。
  1. 静态代码分析工具:一些静态代码分析工具(例如Clang静态分析器)可以检测潜在的内存泄漏问题。这些工具会在编译时分析代码并发现问题,但不会运行时捕获问题。

  2. 自定义内存分配器:你可以实现自定义内存分配器,以跟踪分配和释放的内存块。这可以用于在程序退出时报告未释放的内存。

  3. 内存泄漏检测库:一些第三方库和工具,如LeakSanitizer、Electric Fence等,专门用于检测内存泄漏问题。

综合使用上述工具和技术,可以有效地检测和解决内存泄漏问题。检测内存泄漏是编写高质量C++程序的关键步骤之一。但总的来说,处理内存泄漏最好的方法还是从源头入手,写代码时多进行代码审查,检查代码以查找潜在的内存泄漏问题,特别是在程序的关键部分。

写出高质量C++代码来扼杀内存泄漏,扼杀内存泄漏来写出高质量C++代码。啊这…🤔

在这里插入图片描述

RAII

RAII是“资源获取即初始化(Resource Acquisition Is Initialization)”的缩写,它是C++中一种重要的编程范式和管理资源的惯用法。它基于C++语言的构造函数和析构函数的特性,用于确保在对象生命周期中正确获取和释放资源。RAII的核心思想是利用对象的构造函数来获取资源,而析构函数来释放资源,从而确保资源的正确管理。

如下是RAII的关键原则和应用方式:

  • 构造函数获取资源:在对象构造的时候,资源被分配和初始化。这可以是任何资源,例如动态内存、文件句柄、网络连接等。

  • 析构函数释放资源:当对象超出作用域时,其析构函数会自动被调用,从而释放资源。这确保了无论控制流如何改变,资源都将被正确释放,甚至在异常抛出的情况下也是如此。

  • 异常安全性:利用RAII的方式可以确保资源的安全释放,即使在发生异常时也不会造成资源泄漏。因为对象的析构函数会在异常发生时被自动调用。

智能指针就是RAII思想的一个出色体现,可以更方便地管理动态分配的内存。它是C++中一种重要的资源管理模式,广泛应用于各种情况,包括但不限于文件处理、网络操作、数据库连接、互斥锁和其他资源的管理。使用RAII可以避免手动管理资源的繁琐和错误,使代码更加安全、清晰,并提高可维护性和可靠性。

智能指针原理

智能指针是C++中用于管理动态内存的抽象,它们基于C++语言的特性和模板,通过智能的方式管理资源的生命周期,但是智能指针总的来说还是一个指针,因此智能指针通常重载了*->运算符,以模拟原始指针的行为,使其更容易使用。并且智能指针一般都使用对象的构造函数来获取资源,通常通过动态内存分配。资源的构造发生在智能指针被创建时,当智能指针超出作用域时,其析构函数被调用,用于释放资源。

有些智能指针还包括计数引用,例如share_ptr智能指针通常使用引用计数来跟踪资源的所有者数量。每当一个智能指针指向资源时,引用计数会增加;当一个智能指针不再指向资源时,引用计数会减少。当引用计数变为零时,资源被释放。这确保了资源只在不再需要时才会被释放。总的来说,智能指针的原理一般都包括RAII特性和重载了operator*和opertaor->,具有像指针一样的行为。

智能指针使用

std::auto_ptr

在这里插入图片描述

std::auto_ptr 是 C++98 标准中提供的智能指针之一,用于管理动态分配的对象。然而,它在 C++11 标准中已被弃用,因为它存在一些潜在的安全性和语义问题。std::auto_ptr 的核心思想是实现智能指针,它能够拥有动态分配的对象,允许将对象的所有权从一个 std::auto_ptr 转移到另一个。这是通过在 std::auto_ptr 的复制构造函数和赋值运算符中使用移动语义来实现的。当资源管理对象(通常是 std::auto_ptr)的所有权被转移到另一个对象时,原始资源管理对象会失去对资源的控制,从而防止资源重复释放。

以下是有关 std::auto_ptr 的一些关键特点和限制:

特点限制
所有权转移std::auto_ptr 具有所有权语义,这意味着它可以拥有动态分配的对象,并且可以将对象的所有权从一个 std::auto_ptr 转移到另一个。这使得它可以用于简单的资源管理。
所有权转移的问题虽然所有权转移是 std::auto_ptr 的一个特性,但它也是它的一个问题。当一个 std::auto_ptr 拥有一个对象时,不能再创建另一个拥有相同对象的 std::auto_ptr,因为它会导致资源双重释放的问题。这是 std::auto_ptr 的一个潜在陷阱。
不适用于容器由于上述问题,std::auto_ptr 通常不适合用于容器,如 std::vector 或 std::map,因为容器需要在拷贝元素时具备复制语义。
缺乏共享拥有权与 std::shared_ptr 不同,std::auto_ptr 不能用于多个指针共享相同的对象。这是因为它的所有权转移特性。

总之,std::auto_ptr 是一个过时的智能指针,不推荐在现代 C++ 中使用。推荐使用 std::unique_ptr 或 std::shared_ptr 来更安全地管理动态分配的对象。

如下示例代码展示了auto_ptr的风险,在这个示例中,我们首先创建了两个 std::auto_ptr 指针:autoPtr1 和 autoPtr2。然后,我们将 autoPtr1 的所有权转移给 autoPtr2,这意味着 autoPtr1 不再拥有资源,而 autoPtr2 拥有原来的资源,此时的autoPtr1就会悬空,当我们再次解引用autoPtr1时就会导致程序奔溃。

#include <iostream>
#include <memory>

int main() 
{
    std::auto_ptr<int> autoPtr1(new int(42));
    std::auto_ptr<int> autoPtr2;

    // 将 autoPtr1 的所有权转移给 autoPtr2
    autoPtr2 = autoPtr1;

    // 这将导致 autoPtr1 指向 nullptr,autoPtr2 拥有原来的资源
    std::cout << "autoPtr1: " << *autoPtr1 << std::endl;
    std::cout << "autoPtr2: " << *autoPtr2 << std::endl;

    // 尝试使用 autoPtr1,这会导致未定义行为,因为它已经为空指针
    // 但编译器不会发出警告
    //   
    std::cout << "autoPtr1: " << *autoPtr1 << std::endl;

    return 0;
}

在这里插入图片描述

也可以通过简单的代码来模拟autoptr的资源转移,如下:

template <class T>
class autoPtr
{
public:
    autoPtr(T* ptr)
        :_ptr(ptr)
    {}
    autoPtr(autoPtr<T>& aptr)
        :_ptr(aptr._ptr)
    {
        aptr._ptr = nullptr;
    }
    ~autoPtr()
    {
        if (_ptr) delete _ptr;
    }
    autoPtr<T>& operator=(autoPtr<T>& aptr)
    {
        if (this != &aptr)
        {
            if (_ptr) delete _ptr;
            _ptr = aptr._ptr;
            aptr._ptr = nullptr;
        }
        return *this;
    }

    T* operator->()
    {
        return _ptr;
    }

    T& operator*()
    {
        return *_ptr;
    }

private:
    T* _ptr;
};

std::unique_ptr

在这里插入图片描述

与 std::auto_ptr 不同,std::unique_ptr 是 C++11 标准引入的智能指针,用于管理动态分配的对象。它的名称 “unique” 暗示了它的一个主要特性:每个 std::unique_ptr 只能拥有被管理对象的唯一所有权,这意味着不能有多个 std::unique_ptr 同时指向相同的对象,从而防止资源泄漏,提供了更安全的资源管理。以下是它的一些特性:

特性说明
独占所有权每个 std::unique_ptr 实例只能拥有被管理对象的唯一所有权。这意味着不能有多个 std::unique_ptr 同时指向相同的对象。
移动语义std::unique_ptr 支持移动语义,允许将资源的所有权从一个 std::unique_ptr 移动到另一个。这提供了有效的资源管理和转移。
自定义删除器您可以使用自定义删除器函数来指定 std::unique_ptr 在释放资源时应该如何操作。这可以用于管理不同类型的资源,例如动态分配的数组或使用不同的释放函数。
std::make_uniqueC++14 引入了 std::make_unique 函数模板,用于更方便地创建 std::unique_ptr,它自动推断模板类型参数。
类型安全std::unique_ptr 提供类型安全的资源管理,因为它的类型信息在编译时得以确定。
有效代替std::auto_ptrstd::unique_ptr 是对已弃用的 std::auto_ptr 的现代替代品,提供更安全的资源管理。

当然unique_ptr也存在一些限制,如下:

限制说明
不能进行复制std::unique_ptr 不能直接进行复制,因为它的拷贝构造函数和拷贝赋值运算符已被删除。只能通过移动操作来传递所有权。
不支持共享所有权std::unique_ptr 不支持共享所有权,如果需要多个指针共享同一个资源,应该使用 std::shared_ptr。
无法用于数组std::unique_ptr 通常用于管理单个对象的资源。如果需要管理动态分配的数组,应该使用 std::unique_ptr 的特化版本 std::unique_ptr<T[]> 或 std::vector。
不支持自动指针成员的容器std::unique_ptr 无法直接存储在标准库容器中,因为它的复制构造函数和赋值运算符被删除。如果需要在容器中存储智能指针,应该使用 std::shared_ptr 或 std::weak_ptr。

总之,std::unique_ptr 提供了一种轻量级智能指针,用于管理动态分配的对象,它在许多资源管理场景中非常有用。然而,要注意它的独占性质和不能复制的限制,以及选择适当的智能指针类型以满足特定需求。要简单实现一个unique_ptr只需要简单粗暴的防止它拷贝即可,如下:

template <class T>
class unique_ptr
{
public:
	unique_ptr(T* ptr) : _ptr(ptr)
	{}
	~unique_ptr()
	{
		if (_ptr) delete _ptr;
	}
	T& operator*()
	{
		return *_ptr;
	}
	T* operator->()
	{
		return _ptr;
	}
	unique_ptr(const unique_ptr<T>& uptr) = delete;
	unique_ptr<T>& operator=(const unique_ptr<T>& uptr) = delete;
private:
	T* _ptr;
};

std::shared_ptr

在这里插入图片描述

基于std::unique_ptr的限制,std::shared_ptr 允许多个智能指针共享对同一块内存资源的所有权。当最后一个指向资源的 std::shared_ptr 被销毁或重置时,资源才会被释放。这样才更加的符合我们指针的使用场景。std::shared_ptr 也是 C++ 标准库中的一个智能指针类,以下是shared_ptr的一些特性以及限制:

特性说明
共享所有权std::shared_ptr 允许多个智能指针共享对同一块内存资源的所有权。这通过引用计数的方式实现,当最后一个指向资源的 std::shared_ptr 被销毁或重置时,资源才会被释放。
引用计数内部维护引用计数,跟踪共享的指针数量。每次创建或复制一个 std::shared_ptr,引用计数会增加。每次销毁或重置一个 std::shared_ptr,引用计数会减少。当引用计数变为零时,相关的资源会被释放。
安全的共享在正确使用的情况下,std::shared_ptr 可以避免常见的内存泄漏问题,因为资源会在不再需要时自动释放。
自定义删除器:支持自定义删除器函数,用于在资源释放时执行特定的清理操作。

推荐使用 std::make_shared 来创建 std::shared_ptr,以减少动态内存分配的次数,提高性能。

限制说明
性能开销由于引用计数的维护,std::shared_ptr 的性能开销可能比较高。每次复制或创建 std::shared_ptr 都涉及原子操作,这可能导致在多线程环境中的性能开销。
循环引用问题如果存在循环引用,即 A 持有 B 的 std::shared_ptr,而 B 也持有 A 的 std::shared_ptr,可能导致资源永远不会被释放。为了解决这个问题,可以使用 std::weak_ptr。
不适合所有情况尽管 std::shared_ptr 是一个强大的工具,但它并不适合所有情况。在某些场景下,比如性能要求较高的场景,可能需要考虑其他智能指针或手动内存管理的方式。
不是线程安全的原子操作std::shared_ptr 的引用计数操作是原子的,但它本身并不是线程安全的。如果多个线程同时修改同一个 std::shared_ptr,可能需要额外的同步机制。
不能用于管理动态数组std::shared_ptr 不适用于管理动态数组。为了管理动态数组,应该使用 std::shared_ptr 的数组版本 std::shared_ptr<T[]> 或者更适合的 std::vector。

简单模拟实现shared_ptr:

template <class T>
class shared_ptr
{
public:
	shared_ptr(T* ptr = nullptr) 
		: _ptr(ptr)
		, _preCount(new int(1))
		, _mtx(new std::mutex)
	{}

	shared_ptr(shared_ptr<T>& sp)
		: _ptr(sp._ptr)
		, _preCount(sp._preCount)
		, _mtx(sp._mtx)
	{
		addCount();
	}

	void addCount()
	{
		_mtx->lock();
		++(*_preCount);
		_mtx->unlock();
	}

	void relCount()
	{
		_mtx->lock();
		bool flag = false;
		if (--(*_preCount) == 0 && _ptr)
		{
			delete _ptr;
			delete _preCount;
			flag = true;
		}
		_mtx->unlock();
		if (flag) delete _mtx;
	}

	~shared_ptr()
	{
		relCount();
	}

	T& operator*()
	{
		return *_ptr;
	}

	T* operator->()
	{
		return _ptr;
	}

	shared_ptr<T>& operator=(shared_ptr<T>& sp)
	{
		if (this != &sp)
		{
			relCount();
			_ptr = sp._ptr;
			_preCount = sp._preCount;
			_mtx = sp._mtx;
			addCount();
		}
		return *this;
	}

private:
	T* _ptr;
	int* _preCount;
	std::mutex* _mtx;
};

std::shared_ptr循环引用

在这里插入图片描述

std::shared_ptr 可能会导致循环引用问题,这种问题也被称为循环依赖。循环引用发生在两个或多个对象之间互相持有对方的 std::shared_ptr,导致它们的引用计数永远不会减少到零,从而内存泄漏。如下代码:

class A;
class B;

class A 
{
public:
    wzh::shared_ptr<B> bPtr;
};

class B 
{
public:
    wzh::shared_ptr<A> aPtr;
};

int main() 
{
    wzh::shared_ptr<A> a(new A);
    wzh::shared_ptr<B> b(new B);

    // 形成循环引用
    a->bPtr = b;
    b->aPtr = a;

    return 0;
}

示例中,对象 A 持有指向对象 B 的 shared_ptr,而对象 B 持有指向对象 A 的 shared_ptr,这导致了循环引用。因此,即使在 main 函数结束时,这两个对象的引用计数不会减为零,它们的资源也不会被释放,从而导致内存泄漏。

在这里插入图片描述

在这里插入图片描述

为避免循环引用问题,可以使用 std::weak_ptr 来打破其中一个方向的共享关系。

std::weak_ptr

std::weak_ptr 也是 C++ 标准库中的一个智能指针,用于协助管理动态分配的内存资源,但它不像 std::shared_ptr 那样共享所有权,而是提供了一种弱引用的方式。std::weak_ptr 主要用于解决循环引用问题,避免内存泄漏。简单模拟weak_ptr,代码如下:

	template <class T>
	class weak_ptr
	{
	public:
		weak_ptr(T* ptr) : _ptr(ptr)
		{}

		weak_ptr(const shared_ptr<T>& sp)
			: _ptr(sp._ptr)
		{}

		weak_ptr<T>& operator=(shared_ptr<T>& sp)
		{
			if (_ptr != sp.getPtr())
			{
				_ptr = sp.getPtr();
			}
			return *this;
		}

		T* operator->()
		{
			return _ptr;
		}

		T& operator*()
		{
			return *_ptr;
		}

	private:
		T* _ptr;
	};

在上面的示例中,可以使用 std::weak_ptr 来打破其中一个方向的共享关系。因为 std::weak_ptr 不增加引用计数,只是提供对共享对象的弱引用,不影响资源的释放。如下代码:

class A 
{
public:
    wzh::weak_ptr<B> bPtr;
};

class B 
{
public:
    wzh::weak_ptr<A> aPtr;
};

int main() 
{
   
    wzh::shared_ptr<A> a(new A);
    wzh::shared_ptr<B> b(new B);

    // 形成循环引用
    a->bPtr = b;
    b->aPtr = a;

    return 0;
}

在这里插入图片描述
在这里插入图片描述

总结

文章介绍了编程中经常出现的内存泄漏到底是个什么东西,并将内存泄漏的分类也给归置了一下,顺带介绍了检测内存泄漏的工具。文中还重点介绍了智能指针的实现原理以及智能指针的使用,对auto_ptr、unique_ptr、shared_ptr和weak_ptr这几种进行了详细的介绍,对它们的功能特性以及限制都详细的列了出来,并用简单的代码来模拟实现这几种智能指针。文中还特地介绍了shared_ptr的循环引用,产生原因以及解决方法。

码文不易,如果文章对你有帮助的话就来一个三连支持一下吧🌹🌹🌹🌹

在这里插入图片描述

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

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

相关文章

建模仿真软件 Comsol Multiphysics mac中文版软件介绍

COMSOL Multiphysics mac是一款全球通用的基于高级数值方法和模拟物理场问题的通用软件&#xff0c;拥有、网格划分、研究和优化、求解器、可视化和后处理、仿真 App等相关功能&#xff0c;轻松实现各个环节的流畅进行&#xff0c;它能够解释耦合或多物理现象。 附加产品扩展了…

Postman接口测试,全网最详细教程

Postman的脚本可以导出多种语言的脚本&#xff0c;方便二次维护开发。 Python的requests库&#xff0c;支持python2和python3&#xff0c;用于发送http/https请求 使用unittest进行接口自动化测试 0 1****环境准备 1、安装python &#xff08;使用python2或3都可以&#x…

Spring源码-4.Aware接口、初始化和销毁执行顺序、Scope域

Aware接口 其实在生命周期中&#xff0c;Aware接口也参与进来了&#xff0c;如图所示&#xff1a; 如初始化时的第三步&#xff0c;其实就是调用了Aware相关接口。 以常见的Aware接口举例&#xff1a; 1.BeanNameAware 主要是注入Bean的名字 2.BeanFactoryAware 主要是时注…

ESP32开发日志记录

用过一段时间的ESP8266开发&#xff0c; 是在ubunut下建立的开发环境&#xff0c;现在ESP32更简单&#xff0c;直接在Window下IDE即可完成系统配置、新建工程及编译下载工作&#xff0c;使用起来更加简便 一、生成ESP32的工程运行出错 大概意思的芯片是单核芯片&#xff0c;但…

有什么软件能实现erp、crm、oa、财务系统一体化?

只要你能梳理清楚业务逻辑&#xff0c;没有代码基础也完全可以自己搭建业务系统&#xff0c;比ERP管理系统、工程项目管理系统等等......用简道云就可以轻松实现&#xff1a; 下面来按照题主的需求介绍几个系统&#xff1a; 01 客户关系——CRM客户管理套件 重磅打造客户跟进、…

阿里p8推荐,测试覆盖率工具—Jacoco

测试覆盖率工具 测试过程中根据需求文档和设计文档编写测试用例、执行测试&#xff1b;为了更加全面的覆盖&#xff0c;我们可能还需要理解被测程序的逻辑&#xff0c;需要考虑到每个函数的输入与输出&#xff0c;逻辑分支代码的执行情况&#xff0c;这个时候我们的测试执行情…

鉴源论坛 · 观擎丨基于模型的方法在民机机载软件中的应用

作者 | 蔡喁 上海控安可信软件创新研究院副院长 版块 | 鉴源论坛 观擎 社群 | 添加微信号“TICPShanghai”加入“上海控安51fusa安全社区” 01 基于模型的开发和验证MBDV 模型泛指用于支持软件开发过程或软件验证过程的系统的一组软件方面的抽象表示&#xff0c;在机载软件…

【深度学习】【NLP】如何得到一个分词器,如何训练自定义分词器:从基础到实践

文章目录 什么是分词&#xff1f;分词算法使用Python训练分词器步骤1&#xff1a;选择分词算法步骤2&#xff1a;准备训练语料步骤3&#xff1a;配置分词器参数步骤4&#xff1a;训练分词器步骤5&#xff1a;测试和使用分词器 代码示例&#xff1a;使用SentencePiece训练分词器…

技术分享| anyRTC低延时直播优化

直播系统就是把活动现场的音频或视频信号经数字压缩后&#xff0c;传送到直播多媒体服务器(CDN)上&#xff0c;在互联网上供广大网友或授权特定人群收听或收看。而随着技术的日益更新&#xff0c;人民对于直播的互动性&#xff0c;实时性要求更高了&#xff0c;传统的直播少则几…

C语言编写图形化界面-创建按钮-为其指定样式

文章目录 前置章节指定窗口样式给按钮加边框扁平化按钮复选框样式按钮自动复选框 单选按钮三态按钮自动三态按钮 默认按钮样式&#xff08;对话框Enter键&#xff09; 设置按钮位置和大小封装函数 前置章节 开始之前&#xff0c;需要学习以下章节&#xff1a; 创建窗口 窗口过…

10G传输分析仪SDH表TFN D450S参数详情

D450S 10G SDH系列 SDH/SONET传输测试模块 D450S系列SDH/SPNET传输测试模块是TFN模块化测试产品中的一款。D450S系列可配置在FT100测试平台上&#xff0c;实现广泛的PDH/DSn和SDH/SONET的测试功能&#xff0c;为城域网提供综合的测试方案&#xff0c;是高性价比的网络测试产品…

500内部服务器错误很常见,但解决方法也很常见

500内部服务器错误是一个非常通用的HTTP状态代码,这意味着网站的服务器出现了问题,但服务器无法更具体地说明具体问题是什么。 HTTP 500内部服务器错误的原因 大多数情况下,当页面或网站的编程出现问题时,就会出现此错误,但问题肯定在你这边。这些问题可能是由浏览器中的…

Linux系统之file命令的基本使用

Linux系统之file命令的基本使用 一、file命令介绍1.1 Linux简介1.2 file命令简介 二、file命令的使用帮助2.1 file命令的help帮助信息2.2 file命令的语法解释2.3 file命令的man手册 三、文件类型介绍四、file命令的基本使用4.1 查询file版本4.2 显示文件类型4.3 输出时不显示文…

selenium+python web自动化测试框架项目实战实例教程

自动化测试对程序的回归测试更方便。 由于回归测试的动作和用例是完全设计好的,测试期望的结果也是完全可以预料的,将回归测试自动运行... 可以运行更加繁琐的测试 自动化测试的一个明显好处就是可以在很短的时间内运行更多的测试。学习自动化测试最终目的是应用到实际项目中&…

基于springboot实现校友社交平台管理系统项目【项目源码+论文说明】计算机毕业设计

基于springboot实现校友社交平台管理系统演示 摘要 校友社交系统提供给用户一个校友社交信息管理的网站&#xff0c;最新的校友社交信息让用户及时了解校友社交动向,完成校友社交的同时,还能通过论坛中心进行互动更方便。本系统采用了B/S体系的结构&#xff0c;使用了java技…

C++模板类用作参数传递

前言 在模板类<>传递参数的一种实现。记不住&#xff0c;以此记录。 // dome.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。 // #define _CRT_SECURE_NO_WARNINGS #include <iostream> //#include "tools.h" #include <fu…

一种基于屏幕分辨率的RTSP主子码流切换的多路视频监控的播放方案

技术背景&#xff1a; 用户场景下&#xff0c;存在多个监控场所的100路监控摄像头&#xff0c;例如&#xff1a;大华、海康、宇视、杭州宇泛的枪机、球机、半球、NVR、DVR等不同类型的监控设备&#xff0c;通过视频监控平台进行设备的管理&#xff0c;通过RTSP拉流的方案管理监…

python自动化测试平台开发:自动化测试平台简介

一.测试平台简介 为什么需要测试平台 已有的开源测试平台不能满足需要&#xff0c;不要轻易造轮子 需要公司级别的定制 需要整合公司内部的多套平台 例子&#xff1a;DevOps平台、精准化测试平台、质量监控平台等等 常见的测试平台开发模式 大一统模式&#xff08;适合简单的…

鉴源实验室 | AUTOSAR E2E:车载通信的安全保障

作者 | 沈平 上海控安可信软件创新研究院汽车网络安全组 来源 | 鉴源实验室 社群 | 添加微信号“TICPShanghai”加入“上海控安51fusa安全社区” 随着汽车行业逐步走向电气化、智能化&#xff0c;车载系统的软件和硬件复杂度不断上升。如何确保这些复杂系统中的数据通讯安全和…

Arduino驱动热敏电阻传感器模块

目录 一、简介二、参数性能三、使用方法四、实验现象 一、简介 点击图片购买 热敏电阻传感器模块采用NTC热敏电阻传感器&#xff0c;灵敏度好&#xff0c;PH2.0接口即插即用&#xff0c;防反接&#xff0c;适用于各类开发板。 二、参数性能 电压5V接口3PIN防反接PH2.0杜邦线尺…