(UE4 4.20 ) UE4的Actor生命周期(1) 之 SpawnActor , SpawnActorDeferred 产生 Actor 和 AActor 初始化的执行流程

2023-11-14

https://docs.unrealengine.com/en-us/Programming/UnrealArchitecture/Actors/ActorLifecycle 官方的编程文档中,UE4官方给出了有关Actor生命周期的宝贵资料.

 

Actor生命周期概述图

这里我就跟着资料追着源码剖解一遍游戏运行时产生Actor的函数-----------------SpawnActor和SpawnActorDeferred的产生Actor调用各种函数的流程

 

SpawnActor产生并初始化Actor的流程

World.h

在UE4中我们一般调用来自于 World.h 的各种SpawnActor<T>(....),如下面的

template< class T >
	T* SpawnActor( UClass* Class, FVector const& Location, FRotator const& Rotation, const FActorSpawnParameters& SpawnParameters = FActorSpawnParameters() )
	{
		return CastChecked<T>(SpawnActor(Class, &Location, &Rotation, SpawnParameters),ECastCheckedType::NullAllowed);
	}

SpawnActor<T>各种模板函数的SpawnActor来源于LevelActor.cpp,所以我们来到LevelActor.cpp。

LevelActor.cpp

上面在 Wolrd.h 的各种 SpawnActor 的模板函数都来源于LevelActor.cpp的SpawnActor函数,贴出小部分代码:

在LevelActor.cpp 299 行

AActor* UWorld::SpawnActor( UClass* Class, FTransform const* UserTransformPtr, const FActorSpawnParameters& SpawnParameters )
{
	SCOPE_CYCLE_COUNTER(STAT_SpawnActorTime);
	SCOPE_TIME_GUARD_NAMED_MS(TEXT("SpawnActor Of Type"), Class->GetFName(), 2);
	

	check( CurrentLevel ); 	
	check(GIsEditor || (CurrentLevel == PersistentLevel));

	// Make sure this class is spawnable.
	if( !Class )
	{
		UE_LOG(LogSpawn, Warning, TEXT("SpawnActor failed because no class was specified") );
		return NULL;
	}

#if ENABLE_SPAWNACTORTIMER
	FScopedSpawnActorTimer SpawnTimer(Class->GetFName(), SpawnParameters.bDeferConstruction ? ESpawnActorTimingType::SpawnActorDeferred : ESpawnActorTimingType::SpawnActorNonDeferred);
#endif

往下看来到 LevelActor.cpp 432 行, 可以看到我们的Actor创建其实也是通过NewObject

AActor* const Actor = NewObject<AActor>(LevelToSpawnIn, Class, NewActorName, SpawnParameters.ObjectFlags, Template);

往下看到 LevelActor.cpp 465 行,看到对应Actor生命周期图----Actor的PostSpawnInitialize函数执行

Actor->PostSpawnInitialize(UserTransform, SpawnParameters.Owner, SpawnParameters.Instigator, SpawnParameters.IsRemoteOwned(), SpawnParameters.bNoFail, SpawnParameters.bDeferConstruction);

下面追寻到 Actor.cpp 中去。

Actor.cpp

上面说到Actor的PostSpawnInitialize函数执行,PostSpawnInitialize在 Actor.cpp 的 2816 行

看下面函数小部分源码

void AActor::PostSpawnInitialize(FTransform const& UserSpawnTransform, AActor* InOwner, APawn* InInstigator, bool bRemoteOwned, bool bNoFail, bool bDeferConstruction)
{
	// General flow here is like so
	// - Actor sets up the basics.
	// - Actor gets PreInitializeComponents()
	// - Actor constructs itself, after which its components should be fully assembled
	// - Actor components get OnComponentCreated
	// - Actor components get InitializeComponent
	// - Actor gets PostInitializeComponents() once everything is set up
	//
	// This should be the same sequence for deferred or nondeferred spawning.

	// It's not safe to call UWorld accessor functions till the world info has been spawned.
	UWorld* const World = GetWorld();
	bool const bActorsInitialized = World && World->AreActorsInitialized();

	CreationTime = (World ? World->GetTimeSeconds() : 0.f);

	// Set network role.
	check(Role == ROLE_Authority);
	ExchangeNetRoles(bRemoteOwned);

	USceneComponent* const SceneRootComponent = FixupNativeActorComponents(this);

往下面看,来到 2910 行,看见 PostActorCreated函数

	// Send messages. We've fully spawned
	PostActorCreated();

看下PostActorCreated在 类Actor的声明和定义:

	/**
	 * Called when an actor is done spawning into the world (from UWorld::SpawnActor).
	 * For actors with a root component, the location and rotation will have already been set.
	 * Takes place after any construction scripts have been called
	 */

    void AActor::PostActorCreated()
    {
	    // nothing at the moment
    }

protected 的virtual 函数,这个是我们在AActor类构造函数之后的第一个可以Override的

忘下面看,然后我们到 2914行 的 FinishSpawning 函数执行,比较注意的是这里有个if (!bDeferConstruction) 判断,我们用

SpawnActor<T>时,bDeferConstruction = false,因此可以执行FinishSpawning

// Executes native and BP construction scripts.
// After this, we can assume all components are created and assembled.
if (!bDeferConstruction)
{
	FinishSpawning(UserSpawnTransform, true);
}

来到 FinishSpawning 函数的执行代码,贴出一小部分

void AActor::FinishSpawning(const FTransform& UserTransform, bool bIsDefaultTransform, const FComponentInstanceDataCache* InstanceDataCache)
{
#if ENABLE_SPAWNACTORTIMER
	FScopedSpawnActorTimer SpawnTimer(GetClass()->GetFName(), ESpawnActorTimingType::FinishSpawning);
	SpawnTimer.SetActorName(GetFName());
#endif

	if (ensure(!bHasFinishedSpawning))
	{
		bHasFinishedSpawning = true;

来到 2970行,看到ExecuteConstruction函数的执行

ExecuteConstruction(FinalRootComponentTransform, nullptr, InstanceDataCache, bIsDefaultTransform);

ExecuteConstruction是声明在AActor的函数,但是定义 在ActorConstruction.cpp函数,下面我们到ActorConstruction.cpp去

ActorConstruction.cpp

来到 ActorConstruction.cpp的647行,看到ExecuteConstruction函数,贴出小部分代码

bool AActor::ExecuteConstruction(const FTransform& Transform, const FRotationConversionCache* TransformRotationCache, const FComponentInstanceDataCache* InstanceDataCache, bool bIsDefaultTransform)
{
	check(!IsPendingKill());
	check(!HasAnyFlags(RF_BeginDestroyed|RF_FinishDestroyed));

	// ensure that any existing native root component gets this new transform
	// we can skip this in the default case as the given transform will be the root component's transform
	if (RootComponent && !bIsDefaultTransform)
	{

来到839行,看到OnConstruction执行

// Now run virtual notification
OnConstruction(Transform);

OnConstruction 是声明在 AActor.h 定的 protected 的 virtual 函数, 这个接口我们可以考虑在AActor的子类进行override。

virtual void OnConstruction(const FTransform& Transform) {}

然后再次回到AActor.cpp 的 2974行,看到PostActorConstruction函数的执行

AActor.cpp

AActor.cpp 的 2974行 

PostActorConstruction();

PostActorConstruction函数代码在AActor.cpp的2979行开始,贴出小部分代码:

void AActor::PostActorConstruction()
{
	UWorld* const World = GetWorld();
	bool const bActorsInitialized = World && World->AreActorsInitialized();

	if (bActorsInitialized)
	{
		PreInitializeComponents();
	}

来到 2986行 的,看到 PreInitializeComponents函数的执行

PreInitializeComponents();

PreInitializeComponents 是声明在 AActor.h, 定义在 AActor.cpp 的 protected virtual 函数

virtual void PreInitializeComponents();

void AActor::PreInitializeComponents()
{
	if (AutoReceiveInput != EAutoReceiveInput::Disabled)
	{
		const int32 PlayerIndex = int32(AutoReceiveInput.GetValue()) - 1;

		APlayerController* PC = UGameplayStatics::GetPlayerController(this, PlayerIndex);
		if (PC)
		{
			EnableInput(PC);
		}
		else
		{
			GetWorld()->PersistentLevel->RegisterActorForAutoReceiveInput(this, PlayerIndex);
		}
	}
}

 

下面来到 2995行,看到 InitializeComponents 的执行

// Call InitializeComponent on components
InitializeComponents();

看InitializeComponents函数声明

/** Iterate over components array and call InitializeComponent */
void InitializeComponents();

很可惜的一点是 InitializeComponents 并不是protected virtual 函数,因此无法在 AActor.h 子类中Override

往下面看,来到 3047 行,看到PostInitializeComponents函数的执行, PostInitializeComponents是AActor的protected virtual 函数,可以考虑在 AActor 子类中Override

/** Allow actors to initialize themselves on the C++ side */
virtual void PostInitializeComponents();
void AActor::PostInitializeComponents()
{
	if( !IsPendingKill() )
	{
		bActorInitialized = true;

		FNavigationSystem::OnActorRegistered(*this);
		
		UpdateAllReplicatedComponents();
	}
}

继续往下面走,看到DispatchBeginPlay函数的执行

DispatchBeginPlay();
void AActor::DispatchBeginPlay()
{
	UWorld* World = (!HasActorBegunPlay() && !IsPendingKill() ? GetWorld() : nullptr);

	if (World)
	{
		const uint32 CurrentCallDepth = BeginPlayCallDepth++;

		BeginPlay();

		ensure(BeginPlayCallDepth - 1 == CurrentCallDepth);
		BeginPlayCallDepth = CurrentCallDepth;

		if (bActorWantsDestroyDuringBeginPlay)
		{
			// Pass true for bNetForce as either it doesn't matter or it was true the first time to even 
			// get to the point we set bActorWantsDestroyDuringBeginPlay to true
			World->DestroyActor(this, true); 
		}
	}
}

我们最终可以看到 BeginPlay 函数 的,BeginPlay函数也是AActor的protected virtual函数,可以考虑在AAcctor子类override

/** Overridable native event for when play begins for this actor. */
virtual void BeginPlay();
void AActor::BeginPlay()
{
	ensureMsgf(ActorHasBegunPlay == EActorBeginPlayState::HasNotBegunPlay, TEXT("BeginPlay was called on actor %s which was in state %d"), *GetPathName(), (int32)ActorHasBegunPlay);
	SetLifeSpan( InitialLifeSpan );
	RegisterAllActorTickFunctions(true, false); // Components are done below.

	TInlineComponentArray<UActorComponent*> Components;
	GetComponents(Components);

	ActorHasBegunPlay = EActorBeginPlayState::BeginningPlay;
	for (UActorComponent* Component : Components)
	{
		// bHasBegunPlay will be true for the component if the component was renamed and moved to a new outer during initialization
		if (Component->IsRegistered() && !Component->HasBegunPlay())
		{
			Component->RegisterAllComponentTickFunctions(true);
			Component->BeginPlay();
			ensureMsgf(Component->HasBegunPlay(), TEXT("Failed to route BeginPlay (%s)"), *Component->GetFullName());
		}
		else
		{
			// When an Actor begins play we expect only the not bAutoRegister false components to not be registered
			//check(!Component->bAutoRegister);
		}
	}

	ReceiveBeginPlay();

	ActorHasBegunPlay = EActorBeginPlayState::HasBegunPlay;
}

好吧,整天SpawnActor函数的产生AActor,AActor初始化的流程就差不多走了大概,下面总结下SpawnActor和Actor的初始化流程

SpawnActor产生并初始化Actor的流程图


棕色标注的函数的AActor可改写的,我们可以在AActor的子类中override的。

得注意一点的我,我在追源码并发现“OnActorSpawn”这个并不是函数,而是一个委托,用来通知AActor已经Spawn。在PostSpawnInitialize函数执行之后,位于LevelActor.cpp的 476 行

// Broadcast notification of spawn
OnActorSpawned.Broadcast(Actor);

这个委托是UWorld的委托, 定义在Wolrd.h的1063行

DECLARE_MULTICAST_DELEGATE_OneParam(FOnActorSpawned, AActor*);
/** a delegate that broadcasts a notification whenever an actor is spawned */
FOnActorSpawned OnActorSpawned;

不是函数的话我就不添加到流程图了。

其实在AActor.h就有类似的说明了“AActor初始化顺序”注释

class ENGINE_API AActor : public UObject
{
	/**
	 * The functions of interest to initialization order for an Actor is roughly as follows:
	 * PostLoad/PostActorCreated - Do any setup of the actor required for construction. PostLoad for serialized actors, PostActorCreated for spawned.  
	 * AActor::OnConstruction - The construction of the actor, this is where Blueprint actors have their components created and blueprint variables are initialized
	 * AActor::PreInitializeComponents - Called before InitializeComponent is called on the actor's components
	 * UActorComponent::InitializeComponent - Each component in the actor's components array gets an initialize call (if bWantsInitializeComponent is true for that component)
	 * AActor::PostInitializeComponents - Called after the actor's components have been initialized
	 * AActor::BeginPlay - Called when the level is started
	 */

 

demo演示

UCLASS()
class MYPROJECT4_API ATestActor : public AActor
{
	GENERATED_BODY()
	
        ATestActor();

protected:
	// Called when the game starts or when spawned

	virtual void PostActorCreated() override;
	virtual void OnConstruction(const FTransform& Transform) override;
	virtual void PreInitializeComponents() override;
	virtual void PostInitializeComponents() override;
	virtual void BeginPlay() override;
}

 

ATestActor::ATestActor()
{
	UE_LOG(LogTemp, Error, TEXT("ATestActor Construction"));
}

void ATestActor::PostActorCreated()
{
	Super::PostActorCreated();
	UE_LOG(LogTemp, Error, TEXT("ATestActor::PostActorCreated"));
}

void ATestActor::OnConstruction(const FTransform& Transform)
{
	Super::OnConstruction(Transform);
	UE_LOG(LogTemp, Error, TEXT("ATestActor::OnConstruction"));

}

void ATestActor::PreInitializeComponents()
{
	Super::PreInitializeComponents();
	UE_LOG(LogTemp, Error, TEXT("ATestActor::PreInitializeComponents"));
}

void ATestActor::PostInitializeComponents()
{
	Super::PostInitializeComponents();
	UE_LOG(LogTemp, Error, TEXT("ATestActor::PostInitializeComponents"));
}

void ATestActor::BeginPlay()
{
	Super::BeginPlay();
	UE_LOG(LogTemp, Error, TEXT("ATestActor::BeginPlay"));
}

 

 

SpawnActorDeferred产生并初始化Actor的流程

World.h

在UE4中我们一般调用来自于 World.h 的各种SpawnActorDeferred<T>(....), 如下面的

template< class T >
	T* SpawnActorDeferred(
		UClass* Class,
		FTransform const& Transform,
		AActor* Owner = nullptr,
		APawn* Instigator = nullptr,
		ESpawnActorCollisionHandlingMethod CollisionHandlingOverride = ESpawnActorCollisionHandlingMethod::Undefined
		)
	{
		if( Owner )
		{
			check(this==Owner->GetWorld());
		}
		FActorSpawnParameters SpawnInfo;
		SpawnInfo.SpawnCollisionHandlingOverride = CollisionHandlingOverride;
		SpawnInfo.Owner = Owner;
		SpawnInfo.Instigator = Instigator;
		SpawnInfo.bDeferConstruction = true;
		return (Class != nullptr) ? Cast<T>(SpawnActor(Class, &Transform, SpawnInfo)) : nullptr;
	}

AActor.cpp

SpawnActorDeferred前面流程和SpawnActor是差不多的(PostActorCreated函数执行前面的流程包括PostActorCreated)

有再次来到AActor.cpp 的 2914行

if (!bDeferConstruction)
{
	FinishSpawning(UserSpawnTransform, true);
}

这个bDeferConstruction来自于FActorSpawnParameters结构体的bDeferConstruction

Actor->PostSpawnInitialize(UserTransform, SpawnParameters.Owner, SpawnParameters.Instigator, SpawnParameters.IsRemoteOwned(), SpawnParameters.bNoFail, SpawnParameters.bDeferConstruction);

看SpawnActorDeferredActor<T> 函数的

SpawnInfo.bDeferConstruction = true;

因此SpawnActorDeferred无法执行FinishSpawning(UserSpawnTransform, true);

 

SpawnActorDeferred产生并初始化Actor的流程图

demo演示

代码上上面的一样

void AMyProject4Character::SpawnTestActor()
{
	ATestActor* testActor = GetWorld()->SpawnActorDeferred<ATestActor>(ATestActor::StaticClass(), GetTransform());
	UE_LOG(LogTemp, Error, TEXT("xxxxxxxxxxxxxxxxxxxxxxxx"));
}

上面这么多protected virtual 函数就执行了PostActorCreated,BeginPlay这个在业务逻辑中常用的初始化函数也不执行。

 

参考资料

【1】https://docs.unrealengine.com/en-us/Programming/UnrealArchitecture/Actors/ActorLifecycle

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

(UE4 4.20 ) UE4的Actor生命周期(1) 之 SpawnActor , SpawnActorDeferred 产生 Actor 和 AActor 初始化的执行流程 的相关文章

  • Linux的命令

    Linux的命令分为四个类型 文件操作命令 系统操作命令 文本处理命令和网络操作命令 下面简单介绍一下常用的Linux命令 文件操作命令 ls 列出目录下的所有文件和目录 cd 切换当前目录 mkdir 创建一个新目录 touch 创建新文
  • (下)苹果有开源,但又怎样呢?

    一开始 因为 MacOS X 苹果与 FreeBSD 过往从密 不仅挖来 FreeBSD 创始人 Jordan Hubbard 更是在此基础上开源了 Darwin 但是 苹果并没有给予 Darwin 太多关注 作为苹果的首个开源项目 它算不
  • OpenCV---膨胀与腐蚀

    膨胀 腐蚀 一 膨胀实现dilate import cv2 as cv import numpy as np def dilate demo image 膨胀 print image shape gray cv cvtColor image
  • 【计算机网络系列】物理层①:物理层的基本概念以及数据通信的基础知识

    本文主要介绍物理层的基本概念以及数据通信的基础知识 同时简单谈谈物理层下面的传输媒体 一 物理层基本概念 首先要强调指出 物理层考虑的是怎样才能在连接各种计算机的传输媒体上传输数据比特流 而不是指具体的传输媒体 大家知道 现有的计算机网络中
  • AI,正在疯狂进化,金融大模型来了

    大家好 现在开源社区 更新速度最快的就是 AI 相关的项目了 几天不看 就又多了一些非常优秀的项目 一 FinGPT 之前我就发过各个领域的大语言模型 比如医学领域的 Huatuo LLaMA 也发过法律领域的大语言模型 LaWGPT 现在
  • 解决Windows丢失msvcp120.dll问题

    其实很多用户玩单机游戏或者安装软件的时候就出现过这种问题 如果是新手第一时间会认为是软件或游戏出错了 其实并不是这样 其主要原因就是你电脑系统的该dll文件丢失了或者损坏了 这时你只需下载这个msvcp120 dll文件进行安装 前提是找到
  • 软件结构化设计-架构真题(二十七)

    2019年 进程P有8个页面 页号分别为0 7 状态位等于1和0分别表示在内存和不在内部才能 假设系统给P分配4个存储块 如果进程P要访问页面6不在内存 那么应该淘汰号是多少 答案 页号2 解析 页号1 2 5 7在内部内存里 而2的被访问
  • Mmdetection训练笔记

    1 imgs per gpu表示一块gpu训练的图片数量 imgs per gpu的值会影响终端输出的显示 比如 如果你有一块GPU 训练集有4000张 imgs per gpu设为2的话 终端的输出可能是Epoch 1 50 2000 另
  • 从Vue2到Vue3【五】——新的组件(Fragment、Teleport、Suspense)

    系列文章目录 内容 链接 从Vue2到Vue3 零 Vue3简介 从Vue2到Vue3 一 Composition API 第一章 从Vue2到Vue3 二 Composition API 第二章 从Vue2到Vue3 三 Composit
  • 前端缓存区别记录 SessionStorage和LocalStorage详解

    LocalStorage和SessionStorage之间的主要区别在于浏览器窗口和选项卡之间的数据共享方式不同 LocalStorage可跨浏览器窗口和选项卡间共享 就是说如果在多个选项卡和窗口中打开了一个应用程序 而一旦在其中一个选项卡
  • spi个人笔记

    spi是全双工通讯 收发同时进行 这句话怎么理解 如上图所示 主机产生一组时钟信号 并通过mosi输出8位数据 这个时候 虽然从机没有返回数据 持续低电平 但是因为是 收发同步 所以此时主机已经采集了此次的miso数据 就是说 无论你的目的
  • 【upload-labs 第四关通关攻略】

    一 类型 无法上传php等多种类型 选择 htaccess配置文件 二 htaccess内容 注意 不能命名 就叫 htaccess
  • Java手写数组和案例拓展

    Java手写数组和案例拓展 1 Mermanid代码绘制的思维导图解释实现思路原理 mermaid svg HoH3kyfEhPDhcUh4 font family trebuchet ms verdana arial sans serif
  • js发布——订阅模式的通用实现及取消订阅

    h1 发布 订阅模式的通用实现 h1 p javaScript作为一门解释执行的语言 给对象添加动态职责是理所当然的 所以我们将发布 订阅的功能提取出来 放在一个单独的对象内 p
  • Javascript创建对象的几种方式及优劣

    1 字面量方式 var obj name tom age 20 career network getName function return this name alert obj getName 这种方式适合创建单个对象 2 创建Obje
  • HttpCanary使用指南——各种神奇的插件

    HttpCanary更多资料 点我 作为目前Android平台最强大的抓包工具 HttpCanary从设计之初就规划了插件功能 2 6 0版本之前称为 模组 基于NetBare框架的虚拟网关 拦截器设计 HttpCanary可以实现非常多的
  • 2020春秋招聘图像处理 人工智能方向 各大厂面试常见题整理一(附答案)(阿里腾讯华为字节)

    因为本人近期也要紧临毕业 面临招聘面试 所以整体别人公开的面经 做一个整理 并且加上自己认为的答案 欢迎各位读者对答案进行指正和交流 深度残差的作用 直观上 深度加深 出现梯度消失和梯度爆炸的问题 在论文中 出现了一个奇怪的现象 就是56层
  • Hive命令的使用

    命令行界面 Command Line Interface CLI 是Hive交互最常见也是最方便的方式 在命令行界面可以执行Hive支持的觉大多数功能 如查询 创建等 hive e 有时 并不需要一直打开命令行界面 也就是说执行完查询后立刻
  • Vue-ref用法

    用ref操作模版中的dom元素 1 在模版中 声明ref名称 div ref引用Dom节点 div 2 用法 change this refs chagneBack style color red 用ref操作组件 1 在组件引用中声明re

随机推荐

  • Redis 汇总

    Redis 0 声明 1 概述 1 1 Redis是什么 1 2 Redis优缺点 1 3 为什么要用 Redis 为什么要用缓存 1 4 Redis为什么这么快 2 常用数据结构 2 1 String 应用场景 2 2 List 应用场景
  • Jetpack Compose多平台用于Android和IOS

    JetBrains和外部开源贡献者已经努力工作了几年时间来开发Compose Multiplatform 并最近发布了适用于iOS的Alpha版本 自然地 我们对其功能进行了测试 并决定通过使用该框架在iOS上运行我们的Dribbble复制
  • Matlab中求数据概率分布的方法

    一 问题描述 对已有的一些列数据进行分析 想得到该数据的分布和统计特性 如概率密度函数 概率分布 累计概率密度等等 例如 已有一段时间的声音测量数据 求该数据的分布特性 并给出噪声的95 置信区间统计参数以表征该声音监测数据的总体水平 二
  • HTTP响应的结构是怎么样的?

    HTTP响应由三部分组成 状态行 响应头 响应正文 状态行 包括协议版本的Version 状态码 Status Code 回应短语 响应头 包括搭建服务器的软件 发送响应的时间 回应数据的格式等信息 响应正文 就是响应的具体数据 HTTP请
  • PROJ.4学习——初识PROJ

    PROJ 4介绍 初始认识 前言 PROJ是一个通用的坐标转换软件 它将地理空间坐标从一个坐标系转换为另一个坐标系 这包括地图投影和大地坐标变换 PROJ包含命令行应用程序 可以方便地从文本文件或直接从用户输入转换坐标 除了命令行实用程序之
  • eclipse安装教程(2021最新版)超级易懂到吐血

    第一步 下载JDK 下载地址 http www oracle com technetwork java javase downloads index html 第二步 根据自己电脑的系统 选择相应的版本x64代表64位 x86代表32位 点
  • 螺杆真空泵安装流程图_螺杆式真空泵基本知识送给刚入行的新朋友

    螺杆式真空泵是容积式真空泵中的新兴成员 出现于上世纪90年代前后 发展较晚 但作为一种理想干泵 螺杆式真空泵在面世后获得了快速发展 现在就跟小编去了解一下它的基本知识吧 一 螺杆式真空泵特点 螺杆式真空泵脱胎于螺杆式压缩机与螺杆液体输送泵
  • 精英反向与二次插值改进的黏菌算法-附代码

    精英反向与二次插值改进的黏菌算法 文章目录 精英反向与二次插值改进的黏菌算法 1 黏菌算法 2 改进黏菌算法 2 1 精英反向学习机制 2 2 二次插值方法 3 实验结果 4 参考文献 5 Matlab代码 6 python代码 摘要 针对
  • 关于集合Collection

    集合框架 概念 1 Collection是所有集合的顶级接口 2 集合和数组一样 可以保存一组元素 并且提供了操作元素的相关方法 使用更方便 3 Collection 下面有多种实现类 因此我们有更多的数据结构可以选择 Collection
  • 蓝桥杯2020年第十一届省赛真题-子串分值

    题目 题目链接 题解 思维 考虑每个字符对最终答案的贡献 每个字符的贡献为其左侧连续与之不相同的字符个数 1乘以其右侧与之不相同的字符个数 1 样例 ababc 第一个字符a的贡献 0 1 1 1 2 a ab 第二个字符b的贡献 1 1
  • Java使用poi-tl1.9.1生成Word文档的几个小技巧

    目录 前言 一 poi tl简介 1 什么是poi tl 2 常见的word生成对比 3 poi tl功能点 二 poi tl文档生成 1 模板准备 2 目标参数填充 3 生成效果 三 可能会遇到的问题 1 混合图表生成报错 2 图表参数设
  • Linux /etc/resolv.conf DNS服务器IP地址修改被覆盖问题

    为了临时修改DNS服务器IP地址 可能会选择手动修改 etc resolv conf 文件 而在重启Network Manager服务后 sudo systemctl restart NetworkManager resolv conf 文
  • mvc三层架构(用户信息管理系统)

    mvc三层架构 实战项目 用户信息管理系统 一 三层架构 View 层 用于接收用户提交请求的代码 Service 层 系统的业务逻辑主要在这里完成 Dao 层 直接操作数据库的代码 二 三层架构图 三 用户信息管理系统 利用MVC三层架构
  • 金蝶K3客户端:组件KdSvrMgr无法正常工作 排查分析步骤

    远程组件配置工具无法测试通过 并出错 对于以上错误 在其他的地方还会表现为 拒绝的权限 这样子的信息 其实问题实质是一样的 分析如下 1 远程中间层机器和本机网络不通 可以使用ping命令确认是否网络通畅 如果网络通了还是问题依旧 进入分析
  • LeetCode 448. Find All Numbers Disappeared in an Array

    原题网址 https leetcode com problems find all numbers disappeared in an array Given an array of integers where 1 a i n n siz
  • 多项式与快速傅里叶变换(FFT)

    上次算导老师讲分治高精度乘法 n 1 8左右的复杂度 并且说acm里就有这个 然后我小声bb说acm里高精度快速乘是nlogn的 然后一阵虚因为自己不会FFT 今天算法课又提到了并且我和同学吹牛快速傅里叶变换只要nlogn巴拉巴拉 然后又一
  • 使用kubebuilder结合code-generator开发k8s controller(1)

    为了开了controller 先后分析和尝试了几周 现把步骤和踩的坑记录分享一下 使用kubebuilder结合code generator开发k8s controller 1 使用kubebuilder结合code generator开发
  • 查看matlab中函数源代码的方法

    有几种方法可以实现查看matlab里自带函数的源代码 在命令窗口中输入 1 type 函数名 如 type rgb2gray 或者 type rgb2gray m 即可在命令窗口中显示此函数的源代码 2 open 函数名 如 open rg
  • 数据结构与算法--用c语言建立顺序表以及其相关操作

    一 线性表的介绍 线性表分为顺序表和单链表 线性表是数据结构最基础的结构之一 他们与栈 队列 串和数组都属于线性结构 由n个 n gt 0 个数据特性相同的元素构成的有限序列称为线性表 n称为线性表的长度 n 0时称为空表 对于非空的线性表
  • (UE4 4.20 ) UE4的Actor生命周期(1) 之 SpawnActor , SpawnActorDeferred 产生 Actor 和 AActor 初始化的执行流程

    在https docs unrealengine com en us Programming UnrealArchitecture Actors ActorLifecycle 官方的编程文档中 UE4官方给出了有关Actor生命周期的宝贵资